diff --git a/.vscode/settings.json b/.vscode/settings.json index 8b1e351..49e567b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,18 +5,23 @@ "ASPNETCORE", "Barrick", "bcdfghjklmnpqrstvwxyz", + "Bday", "Beichler", "Bohdi", + "Cobertura", "cref", "CUDA", "Dlib", + "DSCN", "Exif", "Getα", "Greyscale", + "jfif", "mmod", "nosj", "paramref", "Phares", + "Rects", "resnet", "Serilog", "Subfile", @@ -29,4 +34,5 @@ "files.exclude": { "**/.git": false }, + "coverage-gutters.coverageBaseDir": "./.vscode/ReportGenerator/Cobertura/*" } \ No newline at end of file diff --git a/Compare/Compare.cs b/Compare/Compare.cs index 05a016a..8decec5 100644 --- a/Compare/Compare.cs +++ b/Compare/Compare.cs @@ -22,7 +22,7 @@ public class Compare private readonly List<(string Find, string Replace)> _RenameBFindReplace; private readonly List<(string Find, string Replace)> _RenameCFindReplace; private readonly List<(string Find, string Replace)> _SpellingFindReplace; - private readonly Dictionary>> _FilePropertiesKeyValuePairs; + private readonly Dictionary>> _FilePropertiesKeyValuePairs; public Compare(List args, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console) { @@ -41,21 +41,21 @@ public class Compare _IsEnvironment = isEnvironment; _Log = Serilog.Log.ForContext(); _FileKeyValuePairs = new List>(); - _FilePropertiesKeyValuePairs = new Dictionary>>(); + _FilePropertiesKeyValuePairs = new Dictionary>>(); string searchPattern = "*"; long ticks = DateTime.Now.Ticks; List topDirectories = new(); List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection; - Property.Models.Configuration propertyConfiguration = Property.Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory); + Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot); Property.Models.Configuration.Verify(propertyConfiguration); Models.Configuration configuration = Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory, propertyConfiguration); Verify(configuration); - bool reverse = false; Model? model = null; + bool reverse = false; + string outputExtension = ".jpg"; PredictorModel? predictorModel = null; - PropertyLogic propertyLogic = GetPropertyLogic(reverse, model, predictorModel); - if (propertyConfiguration.PopulatePropertyId is null) - throw new NullReferenceException(nameof(propertyConfiguration.PopulatePropertyId)); + Map.Models.MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, propertyConfiguration); + A_Property propertyLogic = GetPropertyLogic(reverse, model, outputExtension, predictorModel, mapLogic); foreach (string spelling in configuration.Spelling) { segments = spelling.Split('|'); @@ -114,7 +114,7 @@ public class Compare if (PossiblyRename(topDirectories, groupCollection)) { topDirectories.Clear(); - _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); groupCollection = Property.Models.Stateless.Container.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories); if (appSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(Property.Models.Stateless.Container.GetGroupCollection)); @@ -123,7 +123,7 @@ public class Compare if (PossiblyRenameB(topDirectories, groupCollection)) { topDirectories.Clear(); - _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); groupCollection = Property.Models.Stateless.Container.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories); if (appSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(Property.Models.Stateless.Container.GetGroupCollection)); @@ -132,7 +132,7 @@ public class Compare if (PossiblyRenameC(topDirectories, groupCollection)) { topDirectories.Clear(); - _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); groupCollection = Property.Models.Stateless.Container.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories); if (appSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(Property.Models.Stateless.Container.GetGroupCollection)); @@ -141,7 +141,7 @@ public class Compare if (PossiblyCorrect(topDirectories, groupCollection)) { topDirectories.Clear(); - _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); groupCollection = Property.Models.Stateless.Container.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories); if (appSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(Property.Models.Stateless.Container.GetGroupCollection)); @@ -154,14 +154,14 @@ public class Compare if (dbFiles.Any()) { topDirectories.Clear(); - _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); groupCollection = Property.Models.Stateless.Container.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories); if (appSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(Property.Models.Stateless.Container.GetGroupCollection)); } - if (_IsEnvironment.Development && propertyConfiguration.PopulatePropertyId.Value && !propertyLogic.KeyValuePairs.Any()) + if (_IsEnvironment.Development && propertyConfiguration.PopulatePropertyId && !mapLogic.KeyValuePairs.Any()) throw new Exception("Copy keyValuePairs-####.json file"); - List containers = Property.Models.Stateless.A_Property.Get(propertyConfiguration, propertyLogic); + List containers = A_Property.Get(propertyConfiguration, propertyLogic); if (!isSilent) { _Log.Information("First pass completed"); @@ -203,7 +203,7 @@ public class Compare _Log.Information(". . ."); } string aPropertyContentCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(A_Property), "[()]"); - ThirdPassToMove(propertyConfiguration, model, predictorModel, propertyLogic, containers, aPropertyContentCollectionDirectory); + ThirdPassToMove(propertyConfiguration, model, predictorModel, mapLogic, propertyLogic, containers, aPropertyContentCollectionDirectory); if (!isSilent) { _Log.Information("Third pass completed"); @@ -215,7 +215,7 @@ public class Compare } _Log.Information(". . ."); } - FourthPassCreateWindowsShortcuts(propertyConfiguration, model, predictorModel, propertyLogic, containers, saveToCollection: false, keepAll: false); + FourthPassCreateWindowsShortcuts(propertyConfiguration, model, predictorModel, mapLogic, propertyLogic, containers, saveToCollection: false, keepAll: false); if (!isSilent) { _Log.Information("Fourth pass completed"); @@ -262,7 +262,7 @@ public class Compare directorySegments = pathSegments[^1].Split(' '); if (!DateTime.TryParseExact(string.Join(' ', directorySegments.Take(3)), "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) throw new Exception("l"); - (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + (season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else if (pathSegments.Length == 1) @@ -270,7 +270,7 @@ public class Compare directorySegments = pathSegments[^1].Split(' '); if (DateTime.TryParseExact(directorySegments[^1], "yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { - (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + (season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else @@ -284,7 +284,7 @@ public class Compare directorySegments = pathSegments[0].Split(' '); if (DateTime.TryParseExact(directorySegments[^1], "yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { - (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + (season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else @@ -295,7 +295,7 @@ public class Compare directorySegments = pathSegments[0].Split(' '); if (DateTime.TryParseExact(directorySegments[^1], "yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { - (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + (season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else @@ -305,22 +305,22 @@ public class Compare { if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(2)), "MMM yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { - (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + (season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(2)), "MMM yy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { - (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + (season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else if (DateTime.TryParseExact(string.Concat(directorySegments[0][..3], ' ', directorySegments[1]), "MMM yy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { - (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + (season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(2)), "MMMM yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { - (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + (season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else @@ -330,12 +330,12 @@ public class Compare { if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(3)), "MMMM dd yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { - (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + (season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(3)), "MMMM d yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { - (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + (season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else @@ -349,12 +349,12 @@ public class Compare directorySegments = pathSegments[^1].Split(' '); if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(3)), "MMMM dd yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { - (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + (season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(3)), "MMMM d yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { - (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); + (season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else @@ -373,7 +373,7 @@ public class Compare throw new NullReferenceException(nameof(configuration.Spelling)); } - private long LogDelta(long ticks, string methodName) + private long LogDelta(long ticks, string? methodName) { long result; if (_Log is null) @@ -384,12 +384,12 @@ public class Compare return result; } - private PropertyLogic GetPropertyLogic(bool reverse, Model? model, PredictorModel? predictorModel) + private A_Property GetPropertyLogic(bool reverse, Model? model, string outputExtension, PredictorModel? predictorModel, Map.Models.MapLogic mapLogic) { - PropertyLogic result; + A_Property result; if (_Configuration?.PropertyConfiguration is null) throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration)); - result = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, reverse, model, predictorModel); + result = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, outputExtension, reverse, model, predictorModel); string fromPrepareForOld = "34720-637858334555170379.tsv"; string fromPrepareForOldFile = Path.Combine(_Configuration.PropertyConfiguration.RootDirectory, fromPrepareForOld); if (File.Exists(fromPrepareForOldFile)) @@ -400,12 +400,12 @@ public class Compare long ticks = DateTime.Now.Ticks; lines = File.ReadAllLines(fromPrepareForOldFile); string resultsDirectory = $"{_Configuration.PropertyConfiguration.RootDirectory} - Results"; - int[]? zeros = (from l in result.IndicesFromNew where l.Value.Any() select l.Value[0]).ToArray(); - lines = (from l in result.IndicesFromNew select string.Concat(l.Key, '\t', string.Join('\t', l.Value))).ToArray(); + int[]? zeros = (from l in mapLogic.IndicesFromNew where l.Value.Any() select l.Value[0]).ToArray(); + lines = (from l in mapLogic.IndicesFromNew select string.Concat(l.Key, '\t', string.Join('\t', l.Value))).ToArray(); if (!Directory.Exists(resultsDirectory)) _ = Directory.CreateDirectory(resultsDirectory); File.WriteAllLines(Path.Combine(resultsDirectory, $"{ticks}.tsv"), lines); - string json = JsonSerializer.Serialize(result.IndicesFromNew, new JsonSerializerOptions { WriteIndented = true }); + string json = JsonSerializer.Serialize(mapLogic.IndicesFromNew, new JsonSerializerOptions { WriteIndented = true }); File.WriteAllText(Path.Combine(resultsDirectory, $"{ticks}.json"), json); foreach (string line in lines) { @@ -453,7 +453,7 @@ public class Compare { if (!_Configuration.DiffPropertyDirectory.EndsWith("{}")) throw new Exception("Invalid directory should end with {}!"); - diffRootDirectory = Property.Models.Stateless.A_Property.GetDiffRootDirectory(_Configuration.DiffPropertyDirectory); + diffRootDirectory = Shared.Models.Stateless.Methods.IProperty.GetDiffRootDirectory(_Configuration.DiffPropertyDirectory); } PropertyCompare.Models.PropertyCompareLogic propertyCompareLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _SpellingFindReplace, diffRootDirectory); if (string.IsNullOrEmpty(_Configuration.DiffPropertyDirectory) || !Directory.Exists(_Configuration.DiffPropertyDirectory)) @@ -742,7 +742,7 @@ public class Compare } } - private void ThirdPassToMove(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, PropertyLogic propertyLogic, List containers, string aPropertyContentCollectionDirectory) + private void ThirdPassToMove(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, Map.Models.MapLogic mapLogic, A_Property propertyLogic, List containers, string aPropertyContentCollectionDirectory) { if (_Log is null) throw new NullReferenceException(nameof(_Log)); @@ -751,7 +751,7 @@ public class Compare int stay = 0; string fileName; string id = " - Id"; - A_Property? property; + Shared.Models.Property? property; string? directoryName; ConsoleKey? consoleKey = null; long ticks = DateTime.Now.Ticks; @@ -773,7 +773,7 @@ public class Compare continue; filteredSourceDirectoryFile = group.FilteredSourceDirectoryFiles[i]; valueCollection.Add(new(property.Id.Value, property.Indices)); - if (!propertyLogic.IndicesFromNew.ContainsKey(property.Id.Value)) + if (!mapLogic.IndicesFromNew.ContainsKey(property.Id.Value)) stay += 1; else if (!fileMoveCollection.Contains(filteredSourceDirectoryFile)) fileMoveCollection.Add(filteredSourceDirectoryFile); @@ -816,16 +816,16 @@ public class Compare File.Move(fileMove, fileName); } for (int i = 1; i < 4; i++) - _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(_Configuration.PropertyConfiguration.RootDirectory); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(_Configuration.PropertyConfiguration.RootDirectory); } } - private void FourthPassCreateWindowsShortcuts(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, PropertyLogic propertyLogic, List containers, bool saveToCollection, bool keepAll) + private void FourthPassCreateWindowsShortcuts(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, Map.Models.MapLogic mapLogic, A_Property propertyLogic, List containers, bool saveToCollection, bool keepAll) { if (_Log is null) throw new NullReferenceException(nameof(_Log)); int stay = 0; - A_Property? property; + Shared.Models.Property? property; ConsoleKey? consoleKey = null; long ticks = DateTime.Now.Ticks; string filteredSourceDirectoryFile; @@ -845,7 +845,7 @@ public class Compare continue; filteredSourceDirectoryFile = group.FilteredSourceDirectoryFiles[i]; valueCollection.Add(new(property.Id.Value, property.Indices)); - if (!propertyLogic.IndicesFromNew.ContainsKey(property.Id.Value)) + if (!mapLogic.IndicesFromNew.ContainsKey(property.Id.Value)) stay += 1; else fileMoveCollection.Add(filteredSourceDirectoryFile); diff --git a/Compare/Compare.csproj b/Compare/Compare.csproj index 5701469..b1e4352 100644 --- a/Compare/Compare.csproj +++ b/Compare/Compare.csproj @@ -10,7 +10,7 @@ Phares.View.by.Distance.Compare false - 5.0.402.104 + 6.0.100.1 Mike Phares Phares true @@ -52,9 +52,10 @@ - - + + + diff --git a/Compare/appsettings.Development.json b/Compare/appsettings.Development.json index d711c71..ced403f 100644 --- a/Compare/appsettings.Development.json +++ b/Compare/appsettings.Development.json @@ -79,28 +79,28 @@ "/zzz Phares Slides/Slides 2015-06-10/Magazine 01" ], "Configuration": { - "DateGroup": "2022-08-14", + "DateGroup": "2022-08-22", "DiffPropertyDirectory": "", "FileNameDirectorySeparator": ".Z.", "ForcePropertyLastWriteTimeToCreationTime": false, - "MaxImagesInDirectoryForTopLevelFirstPass": 50, + "MaxImagesInDirectoryForTopLevelFirstPass": 10, "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", "PopulatePropertyId": true, "PropertiesChangedForProperty": false, - "RootDirectory": "C:/Tmp/Phares/Compare/Images 2022-08-14 - b756859b616424dc98b7742a64c15a8951632473 - III", + "RootDirectory": "C:/Tmp/Phares/Compare/Images 2022-08-22 - b756859b616424dc98b7742a64c15a8951632473 - III", "WriteBitmapDataBytes": false, "IgnoreExtensions": [ ".gif", ".GIF" ], "PropertyContentCollectionFiles": [ - "/Images 2022-08-14 - b756859b616424dc98b7742a64c15a8951632473 - III - Results/A) Property/2022-08-14/[()]/637869381676042455.json", - "/Not-Copy-Copy/Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - Not-Copy-Copy - Results/A) Property/2022-08-14/[()]/637869733124119330.json", - "/Not-Copy-Copy/Images 2018-12-25 - 34a9240ac28b52da97428d7725153a80a757ee6b - Not-Copy-Copy - Results/A) Property/2022-08-14/[()]/637869734240700328.json", - "/Not-Copy-Copy/Images 2018-05-12 - b01d4763d8853b6d6057a3870b2723449726da75 - Not-Copy-Copy - Results/A) Property/2022-08-14/[()]/637869734970730630.json", - "/Not-Copy-Copy/Images 2013-12-15 - d02c8791fa0b130c0bce2d39ee684e50f7ee7a97 - Not-Copy-Copy - Results/A) Property/2022-08-14/[()]/637869743752078399.json", - "/Not-Copy-Copy - Delta/Amazon Drive - Results/A) Property/2022-08-14/[()]/637869744751177715.json", - "/Not-Copy-Copy - Delta/Blackberry - Results/A) Property/2022-08-14/[()]/637869745134124462.json" + "/Images 2022-08-22 - b756859b616424dc98b7742a64c15a8951632473 - III - Results/A) Property/2022-08-22/[()]/637869381676042455.json", + "/Not-Copy-Copy/Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - Not-Copy-Copy - Results/A) Property/2022-08-22/[()]/637869733124119330.json", + "/Not-Copy-Copy/Images 2018-12-25 - 34a9240ac28b52da97428d7725153a80a757ee6b - Not-Copy-Copy - Results/A) Property/2022-08-22/[()]/637869734240700328.json", + "/Not-Copy-Copy/Images 2018-05-12 - b01d4763d8853b6d6057a3870b2723449726da75 - Not-Copy-Copy - Results/A) Property/2022-08-22/[()]/637869734970730630.json", + "/Not-Copy-Copy/Images 2013-12-15 - d02c8791fa0b130c0bce2d39ee684e50f7ee7a97 - Not-Copy-Copy - Results/A) Property/2022-08-22/[()]/637869743752078399.json", + "/Not-Copy-Copy - Delta/Amazon Drive - Results/A) Property/2022-08-22/[()]/637869744751177715.json", + "/Not-Copy-Copy - Delta/Blackberry - Results/A) Property/2022-08-22/[()]/637869745134124462.json" ], "ValidImageFormatExtensions": [ ".bmp", diff --git a/Compare/appsettings.json b/Compare/appsettings.json index c58ae1f..c76cbe3 100644 --- a/Compare/appsettings.json +++ b/Compare/appsettings.json @@ -50,11 +50,11 @@ "WorkingDirectoryName": "PharesApps", "Windows": { "Configuration": { - "DateGroup": "2022-08-14", + "DateGroup": "2022-08-22", "DiffPropertyDirectory": "", "FileNameDirectorySeparator": ".Z.", "ForcePropertyLastWriteTimeToCreationTime": false, - "MaxImagesInDirectoryForTopLevelFirstPass": 50, + "MaxImagesInDirectoryForTopLevelFirstPass": 10, "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", "PopulatePropertyId": true, "PropertiesChangedForProperty": false, @@ -94,13 +94,13 @@ ".GIF" ], "PropertyContentCollectionFiles": [ - "/Images 2022-08-14 - b756859b616424dc98b7742a64c15a8951632473 - III - Results/A) Property/2022-08-14/[()]/637869381676042455.json", - "/Not-Copy-Copy/Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - Not-Copy-Copy - Results/A) Property/2022-08-14/[()]/637869733124119330.json", - "/Not-Copy-Copy/Images 2018-12-25 - 34a9240ac28b52da97428d7725153a80a757ee6b - Not-Copy-Copy - Results/A) Property/2022-08-14/[()]/637869734240700328.json", - "/Not-Copy-Copy/Images 2018-05-12 - b01d4763d8853b6d6057a3870b2723449726da75 - Not-Copy-Copy - Results/A) Property/2022-08-14/[()]/637869734970730630.json", - "/Not-Copy-Copy/Images 2013-12-15 - d02c8791fa0b130c0bce2d39ee684e50f7ee7a97 - Not-Copy-Copy - Results/A) Property/2022-08-14/[()]/637869743752078399.json", - "/Not-Copy-Copy - Delta/Amazon Drive - Results/A) Property/2022-08-14/[()]/637869744751177715.json", - "/Not-Copy-Copy - Delta/Blackberry - Results/A) Property/2022-08-14/[()]/637869745134124462.json" + "/Images 2022-08-22 - b756859b616424dc98b7742a64c15a8951632473 - III - Results/A) Property/2022-08-22/[()]/637869381676042455.json", + "/Not-Copy-Copy/Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - Not-Copy-Copy - Results/A) Property/2022-08-22/[()]/637869733124119330.json", + "/Not-Copy-Copy/Images 2018-12-25 - 34a9240ac28b52da97428d7725153a80a757ee6b - Not-Copy-Copy - Results/A) Property/2022-08-22/[()]/637869734240700328.json", + "/Not-Copy-Copy/Images 2018-05-12 - b01d4763d8853b6d6057a3870b2723449726da75 - Not-Copy-Copy - Results/A) Property/2022-08-22/[()]/637869734970730630.json", + "/Not-Copy-Copy/Images 2013-12-15 - d02c8791fa0b130c0bce2d39ee684e50f7ee7a97 - Not-Copy-Copy - Results/A) Property/2022-08-22/[()]/637869743752078399.json", + "/Not-Copy-Copy - Delta/Amazon Drive - Results/A) Property/2022-08-22/[()]/637869744751177715.json", + "/Not-Copy-Copy - Delta/Blackberry - Results/A) Property/2022-08-22/[()]/637869745134124462.json" ], "ValidImageFormatExtensions": [ ".bmp", diff --git a/Date-Group/Date-Group.csproj b/Date-Group/Date-Group.csproj index c8bef69..7c6f7e7 100644 --- a/Date-Group/Date-Group.csproj +++ b/Date-Group/Date-Group.csproj @@ -10,7 +10,7 @@ Phares.View.by.Distance.Date.Group false - 5.0.402.104 + 6.0.100.1 Mike Phares Phares true diff --git a/Date-Group/DateGroup.cs b/Date-Group/DateGroup.cs index 7839a06..24d07ba 100644 --- a/Date-Group/DateGroup.cs +++ b/Date-Group/DateGroup.cs @@ -19,7 +19,7 @@ public class DateGroup private readonly IsEnvironment _IsEnvironment; private readonly Models.Configuration _Configuration; private readonly List> _FileKeyValuePairs; - private readonly Dictionary>> _FilePropertiesKeyValuePairs; + private readonly Dictionary>> _FilePropertiesKeyValuePairs; public DateGroup(List args, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console) { @@ -34,35 +34,34 @@ public class DateGroup _Exceptions = new List(); _Log = Serilog.Log.ForContext(); _FileKeyValuePairs = new List>(); - _FilePropertiesKeyValuePairs = new Dictionary>>(); - Property.Models.Configuration propertyConfiguration = Property.Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory); + _FilePropertiesKeyValuePairs = new Dictionary>>(); + Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot); Property.Models.Configuration.Verify(propertyConfiguration); Models.Configuration configuration = Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory, propertyConfiguration); Verify(configuration); bool reverse = false; Model? model = null; - PredictorModel? predictorModel = null; _Configuration = configuration; + string outputExtension = ".jpg"; + PredictorModel? predictorModel = null; if (configuration.ByHash is null) throw new NullReferenceException(nameof(configuration.ByHash)); if (configuration.ByCreateDateShortcut is null) throw new NullReferenceException(nameof(configuration.ByCreateDateShortcut)); - if (propertyConfiguration.PopulatePropertyId is null) - throw new NullReferenceException(nameof(propertyConfiguration.PopulatePropertyId)); if (!_IsEnvironment.Development) throw new Exception("This program only allows development environments!"); long ticks = DateTime.Now.Ticks; - PropertyLogic propertyLogic = GetPropertyLogic(reverse, model, predictorModel); + A_Property propertyLogic = GetPropertyLogic(reverse, model, outputExtension, predictorModel); string[] dbFiles = Directory.GetFiles(propertyConfiguration.RootDirectory, "*.db", SearchOption.AllDirectories); foreach (string dbFile in dbFiles) File.Delete(dbFile); if (true || appSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(File.Delete)); for (int i = 1; i < 10; i++) - _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); if (true || appSettings.MaxDegreeOfParallelism < 2) - ticks = LogDelta(ticks, nameof(Property.Models.Stateless.IPath.DeleteEmptyDirectories)); - List containers = Property.Models.Stateless.A_Property.Get(propertyConfiguration, propertyLogic); + ticks = LogDelta(ticks, nameof(Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories)); + List containers = A_Property.Get(propertyConfiguration, propertyLogic); if (configuration.ByCreateDateShortcut.HasValue && configuration.ByCreateDateShortcut.Value) CreateDateShortcut(propertyConfiguration, containers); else @@ -71,15 +70,15 @@ public class DateGroup List directoryInfoCollection = new(); propertyLogic.ParallelWork(ticks, containers, firstPass: true); if (appSettings.MaxDegreeOfParallelism < 2) - ticks = LogDelta(ticks, nameof(PropertyLogic.ParallelWork)); + ticks = LogDelta(ticks, nameof(A_Property.ParallelWork)); if (propertyLogic.ExceptionsDirectories.Any()) throw new Exception(); - if (propertyConfiguration.PopulatePropertyId.Value && (configuration.ByCreateDateShortcut.Value || configuration.ByHash.Value)) + if (propertyConfiguration.PopulatePropertyId && (configuration.ByCreateDateShortcut.Value || configuration.ByHash.Value)) { - if (Property.Models.Stateless.A_Property.Any(containers)) + if (Shared.Models.Stateless.Methods.IProperty.Any(containers)) propertyLogic.ParallelWork(ticks, containers, firstPass: false); if (appSettings.MaxDegreeOfParallelism < 2) - ticks = LogDelta(ticks, nameof(PropertyLogic.ParallelWork)); + ticks = LogDelta(ticks, nameof(A_Property.ParallelWork)); if (propertyLogic.ExceptionsDirectories.Any()) throw new Exception(); } @@ -107,9 +106,9 @@ public class DateGroup throw new NullReferenceException(nameof(configuration.KeepFullPath)); if (configuration?.PropertyConfiguration?.PopulatePropertyId is null) throw new NullReferenceException(nameof(configuration.PropertyConfiguration.PopulatePropertyId)); - if (configuration.PropertyConfiguration.PopulatePropertyId.Value && !configuration.ByCreateDateShortcut.Value && !configuration.ByHash.Value) + if (configuration.PropertyConfiguration.PopulatePropertyId && !configuration.ByCreateDateShortcut.Value && !configuration.ByHash.Value) throw new Exception("Change configuration!"); - if (!configuration.PropertyConfiguration.PopulatePropertyId.Value && configuration.ByHash.Value) + if (!configuration.PropertyConfiguration.PopulatePropertyId && configuration.ByHash.Value) throw new Exception("Change configuration!"); if (configuration.ByCreateDateShortcut.Value && configuration.ByDay.Value && configuration.ByWeek.Value && configuration.BySeason.Value && configuration.ByHash.Value) throw new Exception("Change configuration!"); @@ -147,7 +146,7 @@ public class DateGroup return result; } - private long LogDelta(long ticks, string methodName) + private long LogDelta(long ticks, string? methodName) { long result; if (_Log is null) @@ -185,19 +184,19 @@ public class DateGroup string weekOfYear; string? directory; string seasonValue; - A_Property? property; string directoryName; bool? propertyWrongYear; string topDirectoryName; string[]? matches = null; string[] directorySegments; + Shared.Models.Property? property; DateTime? minimumDateTime = null; List destinationCollection; List directoryNames = new(); - FileHolder filteredSourceDirectoryFileHolder; List topDirectorySegments = new(); StringBuilder destinationDirectoryName = new(); Calendar calendar = new CultureInfo("en-US").Calendar; + Shared.Models.FileHolder filteredSourceDirectoryFileHolder; for (int z = 1; z < 3; z++) { if (z == 1) @@ -222,7 +221,7 @@ public class DateGroup directoryName = Path.GetFileName(check); directorySegments = directoryName.Split(' '); topDirectorySegments.AddRange(directorySegments); - (_, matches) = Property.Models.Stateless.A_Property.IsWrongYear(directorySegments, string.Empty); + (_, matches) = Shared.Models.Stateless.Methods.IProperty.IsWrongYear(directorySegments, string.Empty); if (matches.Any()) break; } @@ -240,7 +239,7 @@ public class DateGroup if (property is null) continue; filteredSourceDirectoryFileHolder = group.SourceDirectoryFileHolderCollection[i]; - minimumDateTime = Property.Models.Stateless.A_Property.GetMinimumDateTime(property); + minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(property); directory = filteredSourceDirectoryFileHolder.DirectoryName; if (string.IsNullOrEmpty(directory)) continue; @@ -261,7 +260,7 @@ public class DateGroup flag = '='; } } - (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(minimumDateTime.Value.DayOfYear); + (season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(minimumDateTime.Value.DayOfYear); if ((from l in topDirectorySegments where l == "Christmas" select true).Any()) seasonValue = string.Empty; else @@ -326,12 +325,12 @@ public class DateGroup return results; } - private PropertyLogic GetPropertyLogic(bool reverse, Model? model, PredictorModel? predictorModel) + private A_Property GetPropertyLogic(bool reverse, Model? model, string outputExtension, PredictorModel? predictorModel) { - PropertyLogic result; + A_Property result; if (_Configuration?.PropertyConfiguration is null) throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration)); - result = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, reverse, model, predictorModel); + result = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, outputExtension, reverse, model, predictorModel); return result; } @@ -427,17 +426,17 @@ public class DateGroup } _Log.Information($"Done moving back {moved} file(s)"); for (int i = 1; i < 10; i++) - _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(_Configuration.PropertyConfiguration.RootDirectory); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(_Configuration.PropertyConfiguration.RootDirectory); } - private static void CreateDateShortcut(Property.Models.Configuration configuration, List containers) + private static void CreateDateShortcut(Property.Models.Configuration configuration, List containers) { string path; string fileName; string directory; int selectedTotal; const int minimum = 3; - List selectedItems; + List selectedItems; List dateTimes; DateTime? minimumDateTime; const int maximumHours = 24; @@ -445,26 +444,26 @@ public class DateGroup WindowsShortcut windowsShortcut; TimeSpan threeStandardDeviationHigh; string aPropertyContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "()"); - foreach (Container container in containers) + foreach (Shared.Models.Container container in containers) { if (!container.Items.Any()) continue; selectedTotal = 0; - threeStandardDeviationHigh = Property.Models.Stateless.A_Property.GetThreeStandardDeviationHigh(minimum, container); + threeStandardDeviationHigh = Shared.Models.Stateless.Methods.IProperty.GetThreeStandardDeviationHigh(minimum, container); if (threeStandardDeviationHigh.TotalHours > maximumHours) threeStandardDeviationHigh = new(maximumHours, 0, 0); for (int i = 0; i < container.Items.Count; i++) { - (i, dateTimes, selectedItems) = Property.Models.Stateless.A_Property.Get(container, threeStandardDeviationHigh, i); + (i, dateTimes, selectedItems) = Shared.Models.Stateless.Methods.IProperty.Get(container, threeStandardDeviationHigh, i); selectedTotal += selectedItems.Count; - foreach (Item item in selectedItems) + foreach (Shared.Models.Item item in selectedItems) { if (item.Property is null) continue; relativePathDirectory = Path.GetDirectoryName(item.RelativePath); if (string.IsNullOrEmpty(relativePathDirectory)) continue; - minimumDateTime = Property.Models.Stateless.A_Property.GetMinimumDateTime(item.Property); + minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property); if (minimumDateTime is null) continue; path = Path.GetFullPath($"{configuration.RootDirectory}{item.RelativePath[..^5]}"); diff --git a/Date-Group/Program.cs b/Date-Group/Program.cs index 4326818..f4f5a8d 100644 --- a/Date-Group/Program.cs +++ b/Date-Group/Program.cs @@ -39,41 +39,41 @@ public class Program if (args is null) throw new Exception("args is null!"); #nullable disable - if (Property.Models.Stateless.A_Property.IsWrongYear("-".Split(' '), "2021").Item1.HasValue) + if (IProperty.IsWrongYear("-".Split(' '), "2021").Item1.HasValue) throw new Exception("-"); - if (Property.Models.Stateless.A_Property.IsWrongYear("Christmass".Split(' '), "2021").Item1.HasValue) + if (IProperty.IsWrongYear("Christmass".Split(' '), "2021").Item1.HasValue) throw new Exception("Christmass"); - if (Property.Models.Stateless.A_Property.IsWrongYear("Christmass 2021".Split(' '), "2021").Item1.Value) + if (IProperty.IsWrongYear("Christmass 2021".Split(' '), "2021").Item1.Value) throw new Exception("Christmass"); - if (Property.Models.Stateless.A_Property.IsWrongYear("Christmass ~2021".Split(' '), "2021").Item1.Value) + if (IProperty.IsWrongYear("Christmass ~2021".Split(' '), "2021").Item1.Value) throw new Exception("Christmass"); - if (Property.Models.Stateless.A_Property.IsWrongYear("Christmass ~2021.4".Split(' '), "2021").Item1.Value) + if (IProperty.IsWrongYear("Christmass ~2021.4".Split(' '), "2021").Item1.Value) throw new Exception("Christmass"); - if (!Property.Models.Stateless.A_Property.IsWrongYear("Christmass 2021".Split(' '), "2025").Item1.Value) + if (!IProperty.IsWrongYear("Christmass 2021".Split(' '), "2025").Item1.Value) throw new Exception("Christmass"); - if (!Property.Models.Stateless.A_Property.IsWrongYear("Christmass ~2021".Split(' '), "2025").Item1.Value) + if (!IProperty.IsWrongYear("Christmass ~2021".Split(' '), "2025").Item1.Value) throw new Exception("Christmass"); - if (!Property.Models.Stateless.A_Property.IsWrongYear("Christmass ~2021.4".Split(' '), "2025").Item1.Value) + if (!IProperty.IsWrongYear("Christmass ~2021.4".Split(' '), "2025").Item1.Value) throw new Exception("Christmass"); - if (Property.Models.Stateless.A_Property.IsWrongYear("England 2017".Split(' '), "2017").Item1.Value) + if (IProperty.IsWrongYear("England 2017".Split(' '), "2017").Item1.Value) throw new Exception("England"); - if (Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael".Split(' '), "2021").Item1.HasValue) + if (IProperty.IsWrongYear("Logan Michael".Split(' '), "2021").Item1.HasValue) throw new Exception("Logan Michael"); - if (Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael 2021".Split(' '), "2021").Item1.Value) + if (IProperty.IsWrongYear("Logan Michael 2021".Split(' '), "2021").Item1.Value) throw new Exception("Logan Michael"); - if (Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael ~2021".Split(' '), "2021").Item1.Value) + if (IProperty.IsWrongYear("Logan Michael ~2021".Split(' '), "2021").Item1.Value) throw new Exception("Logan Michael"); - if (Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael ~2021.4".Split(' '), "2021").Item1.Value) + if (IProperty.IsWrongYear("Logan Michael ~2021.4".Split(' '), "2021").Item1.Value) throw new Exception("Logan Michael"); - if (!Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael 2021".Split(' '), "2025").Item1.Value) + if (!IProperty.IsWrongYear("Logan Michael 2021".Split(' '), "2025").Item1.Value) throw new Exception("Logan Michael"); - if (!Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael ~2021".Split(' '), "2025").Item1.Value) + if (!IProperty.IsWrongYear("Logan Michael ~2021".Split(' '), "2025").Item1.Value) throw new Exception("Logan Michael"); - if (!Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael ~2021.4".Split(' '), "2025").Item1.Value) + if (!IProperty.IsWrongYear("Logan Michael ~2021.4".Split(' '), "2025").Item1.Value) throw new Exception("Logan Michael"); - if (Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael ~2021.4".Split(' '), "2021").Item2[0] != "~2021.4") + if (IProperty.IsWrongYear("Logan Michael ~2021.4".Split(' '), "2021").Item2[0] != "~2021.4") throw new Exception("Logan Michael"); - if (Property.Models.Stateless.A_Property.IsWrongYear("Chelsea's 2nd Birthday =2014".Split(' '), "2014").Item1.Value) + if (IProperty.IsWrongYear("Chelsea's 2nd Birthday =2014".Split(' '), "2014").Item1.Value) throw new Exception("Chelsea"); #nullable restore Shared.Models.Console console = new(); diff --git a/Date-Group/appsettings.Development.json b/Date-Group/appsettings.Development.json index 6ba9bf1..ac7658a 100644 --- a/Date-Group/appsettings.Development.json +++ b/Date-Group/appsettings.Development.json @@ -55,15 +55,15 @@ "ByHash": false, "BySeason": false, "ByWeek": false, - "DateGroup": "2022-08-14", + "DateGroup": "2022-08-22", "FileNameDirectorySeparator": ".Z.", "ForcePropertyLastWriteTimeToCreationTime": false, "KeepFullPath": false, - "MaxImagesInDirectoryForTopLevelFirstPass": 50, + "MaxImagesInDirectoryForTopLevelFirstPass": 10, "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", "PopulatePropertyId": true, "PropertiesChangedForProperty": false, - "RootDirectory": "C:/Tmp/Phares/Compare/Images 2022-08-14 - b756859b616424dc98b7742a64c15a8951632473 - III", + "RootDirectory": "C:/Tmp/Phares/Compare/Images 2022-08-22 - b756859b616424dc98b7742a64c15a8951632473 - III", "WriteBitmapDataBytes": false, "IgnoreExtensions": [ ".gif", diff --git a/FaceRecognitionDotNet/FaceRecognition.cs b/FaceRecognitionDotNet/FaceRecognition.cs index 968952d..6f141c8 100644 --- a/FaceRecognitionDotNet/FaceRecognition.cs +++ b/FaceRecognitionDotNet/FaceRecognition.cs @@ -3,7 +3,6 @@ using DlibDotNet.Dnn; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; -using System.Text; using View_by_Distance.FaceRecognitionDotNet.Dlib.Python; using View_by_Distance.FaceRecognitionDotNet.Extensions; using View_by_Distance.Shared.Models; @@ -11,387 +10,64 @@ using View_by_Distance.Shared.Models.Stateless; namespace View_by_Distance.FaceRecognitionDotNet; -/// -/// Provides the method to find and recognize face methods. This class cannot be inherited. -/// -public sealed class FaceRecognition : DisposableObject +public class FaceRecognition : DisposableObject { - #region Fields - - private readonly ShapePredictor _PosePredictor68Point; - - private readonly ShapePredictor _PosePredictor5Point; - - private readonly LossMmod _CnnFaceDetector; - - private readonly LossMetric _FaceEncoder; - - private readonly FrontalFaceDetector _FaceDetector; - - #endregion - - #region Constructors - - /// - /// Initializes a new instance of the class with the directory path that stores model files. - /// - /// The directory path that stores model files. - /// The model file is not found. - /// The specified directory path is not found. - private FaceRecognition(string directory) - { - if (!Directory.Exists(directory)) - throw new DirectoryNotFoundException(directory); - - string? predictor68PointModel = Path.Combine(directory, FaceRecognitionModels.GetPosePredictorModelLocation()); - if (!File.Exists(predictor68PointModel)) - throw new FileNotFoundException(predictor68PointModel); - - string? predictor5PointModel = Path.Combine(directory, FaceRecognitionModels.GetPosePredictorFivePointModelLocation()); - if (!File.Exists(predictor5PointModel)) - throw new FileNotFoundException(predictor5PointModel); - - string? cnnFaceDetectionModel = Path.Combine(directory, FaceRecognitionModels.GetCnnFaceDetectorModelLocation()); - if (!File.Exists(cnnFaceDetectionModel)) - throw new FileNotFoundException(cnnFaceDetectionModel); - - string? faceRecognitionModel = Path.Combine(directory, FaceRecognitionModels.GetFaceRecognitionModelLocation()); - if (!File.Exists(faceRecognitionModel)) - throw new FileNotFoundException(faceRecognitionModel); - - _FaceDetector?.Dispose(); - _FaceDetector = DlibDotNet.Dlib.GetFrontalFaceDetector(); - - _PosePredictor68Point?.Dispose(); - _PosePredictor68Point = ShapePredictor.Deserialize(predictor68PointModel); - - _PosePredictor5Point?.Dispose(); - _PosePredictor5Point = ShapePredictor.Deserialize(predictor5PointModel); - - _CnnFaceDetector?.Dispose(); - _CnnFaceDetector = LossMmod.Deserialize(cnnFaceDetectionModel); - - _FaceEncoder?.Dispose(); - _FaceEncoder = LossMetric.Deserialize(faceRecognitionModel); - } - - /// - /// Initializes a new instance of the class with the instance that contains model binary datum. - /// - /// The instance that contains model binary datum. - /// is null. - /// The model data is null. - private FaceRecognition(ModelParameter parameter) - { - if (parameter == null) - throw new NullReferenceException(nameof(parameter)); - - if (parameter.PosePredictor5FaceLandmarksModel == null) - throw new NullReferenceException(nameof(parameter.PosePredictor5FaceLandmarksModel)); - - if (parameter.PosePredictor68FaceLandmarksModel == null) - throw new NullReferenceException(nameof(parameter.PosePredictor68FaceLandmarksModel)); - - if (parameter.CnnFaceDetectorModel == null) - throw new NullReferenceException(nameof(parameter.CnnFaceDetectorModel)); - - if (parameter.FaceRecognitionModel == null) - throw new NullReferenceException(nameof(parameter.FaceRecognitionModel)); - - _FaceDetector?.Dispose(); - _FaceDetector = DlibDotNet.Dlib.GetFrontalFaceDetector(); - - _PosePredictor68Point?.Dispose(); - _PosePredictor68Point = ShapePredictor.Deserialize(parameter.PosePredictor68FaceLandmarksModel); - - _PosePredictor5Point?.Dispose(); - _PosePredictor5Point = ShapePredictor.Deserialize(parameter.PosePredictor5FaceLandmarksModel); - - _CnnFaceDetector?.Dispose(); - _CnnFaceDetector = LossMmod.Deserialize(parameter.CnnFaceDetectorModel); - - _FaceEncoder?.Dispose(); - _FaceEncoder = LossMetric.Deserialize(parameter.FaceRecognitionModel); - } - - #endregion - - #region Properties - - /// - /// Gets or sets the custom face detector that user defined. - /// public FaceDetector? CustomFaceDetector { get; set; } - - /// - /// Gets or sets the custom face landmark detector that user defined. - /// public FaceLandmarkDetector? CustomFaceLandmarkDetector { get; set; } - /// - /// Gets or sets the character encoding to convert to array of for internal library. - /// - public static Encoding InternalEncoding + private readonly Model _Model; + private readonly int _NumberOfJitters; + private readonly LossMetric _FaceEncoder; + private readonly LossMmod _CnnFaceDetector; + private readonly int _NumberOfTimesToUpsample; + private readonly PredictorModel _PredictorModel; + private readonly FrontalFaceDetector _FaceDetector; + private readonly ShapePredictor _PosePredictor5Point; + private readonly ShapePredictor _PosePredictor68Point; + + public FaceRecognition(int numberOfTimesToUpsample, int numberOfJitters, PredictorModel predictorModel, Model model, ModelParameter modelParameter) { - get => DlibDotNet.Dlib.Encoding; - set => DlibDotNet.Dlib.Encoding = value ?? Encoding.UTF8; + if (modelParameter is null) + throw new NullReferenceException(nameof(modelParameter)); + if (modelParameter.PosePredictor5FaceLandmarksModel is null) + throw new NullReferenceException(nameof(modelParameter.PosePredictor5FaceLandmarksModel)); + if (modelParameter.PosePredictor68FaceLandmarksModel is null) + throw new NullReferenceException(nameof(modelParameter.PosePredictor68FaceLandmarksModel)); + if (modelParameter.CnnFaceDetectorModel is null) + throw new NullReferenceException(nameof(modelParameter.CnnFaceDetectorModel)); + if (modelParameter.FaceRecognitionModel is null) + throw new NullReferenceException(nameof(modelParameter.FaceRecognitionModel)); + _Model = model; + _PredictorModel = predictorModel; + _NumberOfJitters = numberOfJitters; + _NumberOfTimesToUpsample = numberOfTimesToUpsample; + _FaceDetector?.Dispose(); + _FaceDetector = DlibDotNet.Dlib.GetFrontalFaceDetector(); + _PosePredictor68Point?.Dispose(); + _PosePredictor68Point = ShapePredictor.Deserialize(modelParameter.PosePredictor68FaceLandmarksModel); + _PosePredictor5Point?.Dispose(); + _PosePredictor5Point = ShapePredictor.Deserialize(modelParameter.PosePredictor5FaceLandmarksModel); + _CnnFaceDetector?.Dispose(); + _CnnFaceDetector = LossMmod.Deserialize(modelParameter.CnnFaceDetectorModel); + _FaceEncoder?.Dispose(); + _FaceEncoder = LossMetric.Deserialize(modelParameter.FaceRecognitionModel); } - #endregion - - #region Methods - - /// - /// Returns an enumerable collection of array of bounding boxes of human faces in a image using the cnn face detector. - /// - /// An enumerable collection of images. - /// The number of image looking for faces. Higher numbers find smaller faces. - /// The number of images to include in each GPU processing batch. - /// An enumerable collection of array of found face locations. - /// is null. - public IEnumerable BatchFaceLocations(IEnumerable images, int numberOfTimesToUpsample, int batchSize = 128) - { - if (images == null) - throw new NullReferenceException(nameof(images)); - - List? results = new(); - - Image[]? imagesArray = images.ToArray(); - if (!imagesArray.Any()) - return results; - - IEnumerable[]? rawDetectionsBatched = RawFaceLocationsBatched(imagesArray, numberOfTimesToUpsample, batchSize).ToArray(); - - Image? image = imagesArray[0]; - for (int index = 0; index < rawDetectionsBatched.Length; index++) - { - MModRect[]? faces = rawDetectionsBatched[index].ToArray(); - Location[]? locations = faces.Select(rect => new Location(rect.DetectionConfidence, TrimBound(rect.Rect, image.Width, image.Height), image.Width, image.Height)).ToArray(); - foreach (MModRect? face in faces) - face.Dispose(); - results.Add(locations); - } - - return results; - } - - /// - /// Compare a known face encoding against a candidate encoding to see if they match. - /// - /// A known face encodings. - /// A single face encoding to compare against a known face encoding. - /// The distance between faces to consider it a match. Lower is more strict. The default value is 0.6. - /// A True/False value indicating which known a face encoding matches the face encoding to check. - /// or is null. - /// or . - public static bool CompareFace(FaceEncoding knownFaceEncoding, FaceEncoding faceEncodingToCheck, double tolerance = 0.6d) - { - if (knownFaceEncoding == null) - throw new NullReferenceException(nameof(knownFaceEncoding)); - if (faceEncodingToCheck == null) - throw new NullReferenceException(nameof(faceEncodingToCheck)); - - knownFaceEncoding.ThrowIfDisposed(); - faceEncodingToCheck.ThrowIfDisposed(); - - return FaceDistance(knownFaceEncoding, faceEncodingToCheck) <= tolerance; - } - - /// - /// Compare an enumerable collection of face encodings against a candidate encoding to see if they match. - /// - /// An enumerable collection of known face encodings. - /// A single face encoding to compare against the enumerable collection. - /// The distance between faces to consider it a match. Lower is more strict. The default value is 0.6. - /// An enumerable collection of True/False values indicating which known face encodings match the face encoding to check. - /// or is null. - /// is disposed. Or contains disposed object. - public static IEnumerable CompareFaces(IEnumerable knownFaceEncodings, FaceEncoding faceEncodingToCheck, double tolerance = 0.6d) - { - if (knownFaceEncodings == null) - throw new NullReferenceException(nameof(knownFaceEncodings)); - if (faceEncodingToCheck == null) - throw new NullReferenceException(nameof(faceEncodingToCheck)); - - faceEncodingToCheck.ThrowIfDisposed(); - - FaceEncoding[]? array = knownFaceEncodings.ToArray(); - if (array.Any(encoding => encoding.IsDisposed)) - throw new ObjectDisposedException($"{nameof(knownFaceEncodings)} contains disposed object."); - - List? results = new(); - if (array.Length == 0) - return results; - - foreach (FaceEncoding? faceEncoding in array) - results.Add(FaceDistance(faceEncoding, faceEncodingToCheck) <= tolerance); - - return results; - } - - /// - /// Create a new instance of the class. - /// - /// The directory path that stores model files. - /// The model file is not found. - /// The specified directory path is not found. - public static FaceRecognition Create(string directory) => new(directory); - - /// - /// Create a new instance of the class. - /// - /// The instance that contains model binary datum. - /// is null. - /// The model data is null. - public static FaceRecognition Create(ModelParameter parameter) => new(parameter); - - /// - /// Crop a specified image with enumerable collection of face locations. - /// - /// The image contains a face. - /// The enumerable collection of location rectangle for faces. - /// - /// or is null. - /// is disposed. - public static IEnumerable CropFaces(Image image, IEnumerable locations) - { - if (image == null) - throw new NullReferenceException(nameof(image)); - if (locations == null) - throw new NullReferenceException(nameof(locations)); - - image.ThrowIfDisposed(); - - List? results = new(); - foreach (Location? location in locations) - { - DlibDotNet.Rectangle rect = new(location.Left, location.Top, location.Right, location.Bottom); - DPoint[]? dPoint = new[] - { - new DPoint(rect.Left, rect.Top), - new DPoint(rect.Right, rect.Top), - new DPoint(rect.Left, rect.Bottom), - new DPoint(rect.Right, rect.Bottom), - }; - - int width = (int)rect.Width; - int height = (int)rect.Height; - - switch (image.Mode) - { - case Mode.Rgb: - Matrix? rgb = image.Matrix as Matrix; - results.Add(new Image(DlibDotNet.Dlib.ExtractImage4Points(rgb, dPoint, width, height), - Mode.Rgb)); - break; - case Mode.Greyscale: - Matrix? gray = image.Matrix as Matrix; - results.Add(new Image(DlibDotNet.Dlib.ExtractImage4Points(gray, dPoint, width, height), - Mode.Greyscale)); - break; - } - } - - return results; - } - - /// - /// Compare a face encoding to a known face encoding and get a euclidean distance for comparison face. - /// - /// The face encoding to compare. - /// The face encoding to compare against. - /// The euclidean distance for comparison face. If 0, faces are completely equal. - /// or is null. - /// or is disposed. public static double FaceDistance(FaceEncoding faceEncoding, FaceEncoding faceToCompare) { - if (faceEncoding == null) + if (faceEncoding is null) throw new NullReferenceException(nameof(faceEncoding)); - if (faceToCompare == null) + if (faceToCompare is null) throw new NullReferenceException(nameof(faceToCompare)); - faceEncoding.ThrowIfDisposed(); faceToCompare.ThrowIfDisposed(); - if (faceEncoding.Encoding.Size == 0) return 0; - using Matrix? diff = faceEncoding.Encoding - faceToCompare.Encoding; return DlibDotNet.Dlib.Length(diff); } - /// - /// Compare an enumerable collection of face encoding to a known face encoding and get an enumerable collection of euclidean distance for comparison face. - /// - /// The enumerable collection of face encoding to compare. - /// The face encoding to compare against. - /// The enumerable collection of euclidean distance for comparison face. If 0, faces are completely equal. - /// or is null. - /// is disposed. Or contains disposed object. - public static List FaceDistances(IEnumerable faceEncodings, FaceEncoding faceToCompare) - { - if (faceEncodings == null) - throw new NullReferenceException(nameof(faceEncodings)); - if (faceToCompare == null) - throw new NullReferenceException(nameof(faceToCompare)); - - faceToCompare.ThrowIfDisposed(); - - FaceEncoding[]? array = faceEncodings.ToArray(); - if (array.Any(encoding => encoding.IsDisposed)) - throw new ObjectDisposedException($"{nameof(faceEncodings)} contains disposed object."); - - List? results = new(); - if (array.Length == 0) - return results; - - foreach (FaceEncoding? faceEncoding in array) - using (Matrix? diff = faceEncoding.Encoding - faceToCompare.Encoding) - results.Add(DlibDotNet.Dlib.Length(diff)); - - return results; - } - - /// - /// Returns an enumerable collection of face feature data corresponds to all faces in specified image. - /// - /// The image contains faces. The image can contain multiple faces. - /// The enumerable collection of location rectangle for faces. If specified null, method will find face locations. - /// The number of times to re-sample the face when calculating encoding. - /// The dimension of vector which be returned from detector. - /// The model of face detector to detect in image. If is not null, this value is ignored. - /// An enumerable collection of face feature data corresponds to all faces in specified image. - /// is null. - /// contains no elements. - /// or this object or custom face landmark detector is disposed. - /// is not supported. - public List FaceEncodings(Image image, int numberOfTimesToUpsample, IEnumerable? knownFaceLocation, int numberOfJitters, PredictorModel predictorModel, Model model) - { - if (image == null) - throw new NullReferenceException(nameof(image)); - if (predictorModel == PredictorModel.Custom) - throw new NotSupportedException("FaceRecognition.PredictorModel.Custom is not supported."); - - if (knownFaceLocation != null && !knownFaceLocation.Any()) - throw new InvalidOperationException($"{nameof(knownFaceLocation)} contains no elements."); - - image.ThrowIfDisposed(); - ThrowIfDisposed(); - - List rawLandmarks = RawFaceLandmarks(image, numberOfTimesToUpsample, knownFaceLocation, predictorModel, model); - - List results = new(); - foreach (FullObjectDetection landmark in rawLandmarks) - { - FaceEncoding? ret = new(FaceRecognitionModelV1.ComputeFaceDescriptor(_FaceEncoder, image, landmark, numberOfJitters)); - landmark.Dispose(); - results.Add(ret); - } - - return results; - } - private static FacePoint[] Join(IEnumerable facePoints1, IEnumerable facePoints2) { List results = new(); @@ -400,108 +76,224 @@ public sealed class FaceRecognition : DisposableObject return results.ToArray(); } - /// - /// Returns an enumerable collection of dictionary of face parts locations (eyes, nose, etc) for each face in the image. - /// - /// The image contains faces. The image can contain multiple faces. - /// The enumerable collection of location rectangle for faces. If specified null, method will find face locations. - /// The dimension of vector which be returned from detector. - /// The model of face detector to detect in image. If is not null, this value is ignored. - /// An enumerable collection of dictionary of face parts locations (eyes, nose, etc). - /// is null. - /// contains no elements. - /// or this object or custom face landmark detector is disposed. - /// The custom face landmark detector is not ready. - public List<(FacePart, FacePoint[])[]> GetFaceLandmarkCollection(Image faceImage, int numberOfTimesToUpsample, IEnumerable? faceLocations, PredictorModel predictorModel, Model model) + private static Location TrimBound(double detectionConfidence, DlibDotNet.Rectangle rectangle, int width, int height, int facesCount) => + new( + Math.Min(rectangle.Bottom, height), + detectionConfidence, + height, + Math.Max(rectangle.Left, 0), + Math.Min(rectangle.Right, width), + Math.Max(rectangle.Top, 0), + width, + facesCount + ); + + private List<(FacePart, FacePoint[])> GetFaceParts(FullObjectDetection fullObjectDetection) { - List<(FacePart, FacePoint[])[]> results = new(); - if (faceImage == null) - throw new NullReferenceException(nameof(faceImage)); - if (faceLocations != null && !faceLocations.Any()) - throw new InvalidOperationException($"{nameof(faceLocations)} contains no elements."); - faceImage.ThrowIfDisposed(); - ThrowIfDisposed(); - if (predictorModel == PredictorModel.Custom) - throw new NotImplementedException(); - List fullObjectDetections = RawFaceLandmarks(faceImage, numberOfTimesToUpsample, faceLocations, predictorModel, model); - List landmarksCollection = fullObjectDetections.Select(landmark => Enumerable.Range(0, (int)landmark.Parts) - .Select(index => new FacePoint(index, landmark.GetPart((uint)index).X, landmark.GetPart((uint)index).Y)).ToArray()).ToList(); - foreach (FullObjectDetection? landmark in fullObjectDetections) - landmark.Dispose(); - List<(FacePart, FacePoint[])> collection; - foreach (FacePoint[] facePoints in landmarksCollection) + List<(FacePart, FacePoint[])> results = new(); + FacePoint[] facePoints = Enumerable.Range(0, (int)fullObjectDetection.Parts) + .Select(index => new FacePoint(index, fullObjectDetection.GetPart((uint)index).X, fullObjectDetection.GetPart((uint)index).Y)) + .ToArray(); + switch (_PredictorModel) { - collection = new(); - switch (predictorModel) - { - case PredictorModel.Custom: - throw new NotImplementedException(); - case PredictorModel.Large: - if (facePoints.Length != 68) - continue; - collection.Add(new(FacePart.Chin, facePoints.Skip(0).Take(17).ToArray())); - collection.Add(new(FacePart.LeftEyebrow, facePoints.Skip(17).Take(5).ToArray())); - collection.Add(new(FacePart.RightEyebrow, facePoints.Skip(22).Take(5).ToArray())); - collection.Add(new(FacePart.NoseBridge, facePoints.Skip(27).Take(5).ToArray())); - collection.Add(new(FacePart.NoseTip, facePoints.Skip(31).Take(5).ToArray())); - collection.Add(new(FacePart.LeftEye, facePoints.Skip(36).Take(6).ToArray())); - collection.Add(new(FacePart.RightEye, facePoints.Skip(42).Take(6).ToArray())); - collection.Add(new(FacePart.TopLip, Join(facePoints.Skip(48).Take(7), facePoints.Skip(60).Take(5)))); - collection.Add(new(FacePart.BottomLip, Join(facePoints.Skip(55).Take(5), facePoints.Skip(65).Take(3)))); - break; - case PredictorModel.Small: - if (facePoints.Length != 5) - continue; - collection.Add(new(FacePart.RightEye, facePoints.Skip(0).Take(2).ToArray())); - collection.Add(new(FacePart.LeftEye, facePoints.Skip(2).Take(2).ToArray())); - collection.Add(new(FacePart.NoseTip, facePoints.Skip(4).Take(1).ToArray())); - break; - } - results.Add(collection.ToArray()); + case PredictorModel.Custom: + throw new NotImplementedException(); + case PredictorModel.Large: + if (facePoints.Length == 68) + { + results.Add(new(FacePart.Chin, facePoints.Skip(0).Take(17).ToArray())); + results.Add(new(FacePart.LeftEyebrow, facePoints.Skip(17).Take(5).ToArray())); + results.Add(new(FacePart.RightEyebrow, facePoints.Skip(22).Take(5).ToArray())); + results.Add(new(FacePart.NoseBridge, facePoints.Skip(27).Take(5).ToArray())); + results.Add(new(FacePart.NoseTip, facePoints.Skip(31).Take(5).ToArray())); + results.Add(new(FacePart.LeftEye, facePoints.Skip(36).Take(6).ToArray())); + results.Add(new(FacePart.RightEye, facePoints.Skip(42).Take(6).ToArray())); + results.Add(new(FacePart.TopLip, Join(facePoints.Skip(48).Take(7), facePoints.Skip(60).Take(5)))); + results.Add(new(FacePart.BottomLip, Join(facePoints.Skip(55).Take(5), facePoints.Skip(65).Take(3)))); + } + break; + case PredictorModel.Small: + if (facePoints.Length == 5) + { + results.Add(new(FacePart.RightEye, facePoints.Skip(0).Take(2).ToArray())); + results.Add(new(FacePart.LeftEye, facePoints.Skip(2).Take(2).ToArray())); + results.Add(new(FacePart.NoseTip, facePoints.Skip(4).Take(1).ToArray())); + } + break; } return results; } - /// - /// Returns an enumerable collection of face location correspond to all faces in specified image. - /// - /// The image contains faces. The image can contain multiple faces. - /// The number of times to up-sample the image when finding faces. - /// The model of face detector to detect in image. - /// An enumerable collection of face location correspond to all faces in specified image. - /// is null. - /// or this object is disposed. - public List FaceLocations(Model model, Image image, int numberOfTimesToUpsample, bool sortByNormalizedPixelPercentage) + private MModRect[] GetMModRects(Image image) { - if (image == null) - throw new NullReferenceException(nameof(image)); + switch (_Model) + { + case Model.Cnn: + return CnnFaceDetectionModelV1.Detect(_CnnFaceDetector, image, _NumberOfTimesToUpsample).ToArray(); + case Model.Hog: + IEnumerable>? locations = SimpleObjectDetector.RunDetectorWithUpscale2(_FaceDetector, image, (uint)_NumberOfTimesToUpsample); + return locations.Select(l => new MModRect { Rect = l.Item1, DetectionConfidence = l.Item2 }).ToArray(); + case Model.Custom: + if (CustomFaceDetector is null) + throw new NotSupportedException("The custom face detector is not ready."); + return CustomFaceDetector.Detect(image, _NumberOfTimesToUpsample).Select(rect => new MModRect + { + Rect = new DlibDotNet.Rectangle(rect.Left, rect.Top, rect.Right, rect.Bottom), + DetectionConfidence = rect.Confidence + }).ToArray(); + default: + throw new Exception(); + } + } + public List FaceLocations(Image image, bool sortByNormalizedPixelPercentage) + { + if (image is null) + throw new NullReferenceException(nameof(image)); image.ThrowIfDisposed(); ThrowIfDisposed(); - List results = new(); - foreach (MModRect? face in RawFaceLocations(image, numberOfTimesToUpsample, model)) + IEnumerable faces = GetMModRects(image); + foreach (MModRect? face in faces) { - Location? ret = TrimBound(face.Rect, image.Width, image.Height); - double confidence = face.DetectionConfidence; + Location location = TrimBound(face.DetectionConfidence, face.Rect, image.Width, image.Height, faces.Count()); face.Dispose(); - results.Add(new Location(confidence, ret, image.Width, image.Height)); + results.Add(location); } if (sortByNormalizedPixelPercentage) + { results = (from l in results orderby l.NormalizedPixelPercentage select l).ToList(); + int?[] normalizedPixelPercentageCollection = Shared.Models.Stateless.Methods.ILocation.GetInts(results); + int normalizedPixelPercentageDistinctCount = normalizedPixelPercentageCollection.Distinct().Count(); + if (normalizedPixelPercentageDistinctCount != normalizedPixelPercentageCollection.Length) + throw new Exception("Not distinct!"); + } + return results; + } + + private List GetFullObjectDetections(Image image, List locations) + { + List results = new(); + if (_PredictorModel == PredictorModel.Custom) + { + if (CustomFaceLandmarkDetector is null) + throw new NullReferenceException(nameof(CustomFaceLandmarkDetector)); + foreach (Location location in locations) + { + FullObjectDetection fullObjectDetection = CustomFaceLandmarkDetector.Detect(image, location); + results.Add(fullObjectDetection); + } + } + else + { + ShapePredictor posePredictor = _PredictorModel switch { PredictorModel.Large => _PosePredictor68Point, PredictorModel.Small => _PosePredictor5Point, _ => throw new Exception() }; + foreach (Location location in locations) + { + DlibDotNet.Rectangle rectangle = new(location.Left, location.Top, location.Right, location.Bottom); + FullObjectDetection fullObjectDetection = posePredictor.Detect(image.Matrix, rectangle); + results.Add(fullObjectDetection); + } + } + return results; + } + + private List GetLocations(Image image, bool sortByNormalizedPixelPercentage) + { + List results = new(); + MModRect[] mModRects = GetMModRects(image); + if (mModRects.Any()) + { + Location location; + foreach (MModRect? mModRect in mModRects) + { + location = TrimBound(mModRect.DetectionConfidence, mModRect.Rect, image.Width, image.Height, mModRects.Length); + mModRect.Dispose(); + results.Add(location); + } + } + if (sortByNormalizedPixelPercentage) + { + results = (from l in results orderby l.NormalizedPixelPercentage select l).ToList(); + int?[] normalizedPixelPercentageCollection = Shared.Models.Stateless.Methods.ILocation.GetInts(results); + int normalizedPixelPercentageDistinctCount = normalizedPixelPercentageCollection.Distinct().Count(); + if (normalizedPixelPercentageDistinctCount != normalizedPixelPercentageCollection.Length) + throw new Exception("Not distinct!"); + } + return results; + } + + public List<(Location, FaceEncoding?, Dictionary?)> GetCollection(Image image, bool includeFaceEncoding, bool includeFaceParts, bool sortByNormalizedPixelPercentage) + { + List<(Location, FaceEncoding?, Dictionary?)> results = new(); + if (image is null) + throw new NullReferenceException(nameof(image)); + image.ThrowIfDisposed(); + ThrowIfDisposed(); + if (_PredictorModel == PredictorModel.Custom) + throw new NotSupportedException("FaceRecognition.PredictorModel.Custom is not supported."); + List locations = GetLocations(image, sortByNormalizedPixelPercentage); + List fullObjectDetections = GetFullObjectDetections(image, locations); + if (fullObjectDetections.Count != locations.Count) + throw new Exception(); + List<(Location Location, List FaceEncodings, List> FaceParts)> collection = new(); + foreach (Location location in locations) + collection.Add(new(location, new(), new())); + if (locations.Count != collection.Count) + throw new Exception(); + if (!includeFaceEncoding) + { + for (int i = 0; i < collection.Count; i++) + collection[i].FaceEncodings.Add(null); + } + else + { + Matrix doubles; + FaceEncoding faceEncoding; + for (int i = 0; i < collection.Count; i++) + { + doubles = FaceRecognitionModelV1.ComputeFaceDescriptor(_FaceEncoder, image, fullObjectDetections[i], _NumberOfJitters); + faceEncoding = new(doubles); + collection[i].FaceEncodings.Add(faceEncoding); + } + } + if (!includeFaceParts) + { + for (int i = 0; i < collection.Count; i++) + collection[i].FaceParts.Add(new()); + } + else + { + List<(FacePart, FacePoint[])> faceParts; + for (int i = 0; i < collection.Count; i++) + { + faceParts = GetFaceParts(fullObjectDetections[i]); + collection[i].FaceParts.Add(faceParts); + } + } + foreach (FullObjectDetection fullObjectDetection in fullObjectDetections) + fullObjectDetection.Dispose(); + const int indexZero = 0; + Dictionary keyValuePairs; + foreach ((Location location, List faceEncodings, List> faceParts) in collection) + { + if (faceEncodings.Count != 1 || faceParts.Count != 1) + continue; + if (!faceParts[indexZero].Any()) + results.Add(new(location, faceEncodings[indexZero], null)); + else + { + keyValuePairs = new(); + foreach ((FacePart facePart, FacePoint[] facePoints) in faceParts[indexZero]) + keyValuePairs.Add(facePart, facePoints); + results.Add(new(location, faceEncodings[indexZero], keyValuePairs)); + } + } return results; } - /// - /// Creates an from the array. - /// - /// The array contains face encoding data. - /// The this method creates. - /// is null. - /// must be 128. public static FaceEncoding LoadFaceEncoding(double[] encoding) { - if (encoding == null) + if (encoding is null) throw new NullReferenceException(nameof(encoding)); if (encoding.Length != 128) { @@ -516,25 +308,29 @@ public sealed class FaceRecognition : DisposableObject return new FaceEncoding(matrix); } + public static Image LoadImageFile(string file, Mode mode = Mode.Rgb) + { + if (!File.Exists(file)) + throw new FileNotFoundException(file); + return mode switch + { + Mode.Rgb => new Image(DlibDotNet.Dlib.LoadImageAsMatrix(file), mode), + Mode.Greyscale => new Image(DlibDotNet.Dlib.LoadImageAsMatrix(file), mode), + _ => throw new NotImplementedException() + }; + } + #pragma warning disable CA1416 - /// - /// Creates an from the specified existing bitmap image. - /// - /// The from which to create the new . - /// The this method creates. - /// is null. - /// The specified is not supported. public static Image? LoadImage(Bitmap bitmap) { + Mode mode; + int dstChannel; + int srcChannel; int width = bitmap.Width; int height = bitmap.Height; - System.Drawing.Rectangle rect = new(0, 0, width, height); PixelFormat format = bitmap.PixelFormat; - - Mode mode; - int srcChannel; - int dstChannel; + System.Drawing.Rectangle rect = new(0, 0, width, height); switch (format) { case PixelFormat.Format8bppIndexed: @@ -556,13 +352,10 @@ public sealed class FaceRecognition : DisposableObject default: throw new ArgumentOutOfRangeException($"{nameof(bitmap)}", $"The specified {nameof(PixelFormat)} is not supported."); } - BitmapData? data = null; - try { data = bitmap.LockBits(rect, ImageLockMode.ReadOnly, format); - unsafe { byte[]? array = new byte[width * height * dstChannel]; @@ -586,12 +379,10 @@ public sealed class FaceRecognition : DisposableObject { byte* src = (byte*)data.Scan0; int stride = data.Stride; - for (int h = 0; h < height; h++) { int srcOffset = h * stride; int dstOffset = h * width * dstChannel; - for (int w = 0; w < width; w++) { // BGR order to RGB order @@ -603,7 +394,6 @@ public sealed class FaceRecognition : DisposableObject } break; } - IntPtr ptr = (IntPtr)pArray; switch (mode) { @@ -620,209 +410,33 @@ public sealed class FaceRecognition : DisposableObject if (data != null) bitmap.UnlockBits(data); } - return null; } + public static List FaceDistances(IEnumerable faceEncodings, FaceEncoding faceToCompare) + { + List? results = new(); + if (faceEncodings is null) + throw new NullReferenceException(nameof(faceEncodings)); + if (faceToCompare is null) + throw new NullReferenceException(nameof(faceToCompare)); + faceToCompare.ThrowIfDisposed(); + FaceEncoding[] array = faceEncodings.ToArray(); + if (array.Any(encoding => encoding.IsDisposed)) + throw new ObjectDisposedException($"{nameof(faceEncodings)} contains disposed object."); + if (array.Length == 0) + return results; + foreach (FaceEncoding faceEncoding in array) + using (Matrix diff = faceEncoding.Encoding - faceToCompare.Encoding) + results.Add(DlibDotNet.Dlib.Length(diff)); + return results; + } + #pragma warning restore CA1416 - /// - /// Creates an from the array. - /// - /// The array contains image data. - /// The number of rows in a image data. - /// The number of columns in a image data. - /// The stride width in bytes. - /// A image color mode. - /// The this method creates. - /// is null. - /// is less than 0. - /// is less than 0. - /// is less than 0. - /// is less than . - /// x is less than . - public static Image? LoadImage(byte[] array, int row, int column, int stride, Mode mode) - { - if (array == null) - throw new NullReferenceException(nameof(array)); - if (row < 0) - throw new ArgumentOutOfRangeException($"{nameof(row)}", $"{nameof(row)} is less than 0."); - if (column < 0) - throw new ArgumentOutOfRangeException($"{nameof(column)}", $"{nameof(column)} is less than 0."); - if (stride < 0) - throw new ArgumentOutOfRangeException($"{nameof(stride)}", $"{nameof(stride)} is less than 0."); - if (stride < column) - throw new ArgumentOutOfRangeException($"{nameof(stride)}", $"{nameof(stride)} is less than {nameof(column)}."); - int min = row * stride; - if (!(array.Length >= min)) - throw new ArgumentOutOfRangeException("", $"{nameof(row)} x {nameof(stride)} is less than {nameof(Array)}.{nameof(Array.Length)}."); - - unsafe - { - fixed (byte* p = &array[0]) - { - IntPtr ptr = (IntPtr)p; - switch (mode) - { - case Mode.Rgb: - return new Image(new Matrix(ptr, row, column, stride), Mode.Rgb); - case Mode.Greyscale: - return new Image(new Matrix(ptr, row, column, stride), Mode.Greyscale); - } - } - } - - return null; - } - - /// - /// Creates an from the unmanaged memory pointer indicates array image data. - /// - /// The unmanaged memory pointer indicates array image data. - /// The number of rows in a image data. - /// The number of columns in a image data. - /// The stride width in bytes. - /// A image color mode. - /// The this method creates. - /// is . - /// is less than 0. - /// is less than 0. - /// is less than 0. - /// is less than . - public static Image? LoadImage(IntPtr array, int row, int column, int stride, Mode mode) - { - if (array == IntPtr.Zero) - throw new ArgumentException($"{nameof(array)} is {nameof(IntPtr)}.{nameof(IntPtr.Zero)}", nameof(array)); - if (row < 0) - throw new ArgumentOutOfRangeException($"{nameof(row)}", $"{nameof(row)} is less than 0."); - if (column < 0) - throw new ArgumentOutOfRangeException($"{nameof(column)}", $"{nameof(column)} is less than 0."); - if (stride < 0) - throw new ArgumentOutOfRangeException($"{nameof(stride)}", $"{nameof(stride)} is less than 0."); - if (stride < column) - throw new ArgumentOutOfRangeException($"{nameof(stride)}", $"{nameof(stride)} is less than {nameof(column)}."); - - return mode switch - { - Mode.Rgb => new Image(new Matrix(array, row, column, stride), mode), - Mode.Greyscale => new Image(new Matrix(array, row, column, stride), mode), - _ => null, - }; - } - - /// - /// Creates an from the specified path. - /// - /// A string that contains the path of the file from which to create the . - /// A image color mode. - /// The this method creates. - /// The specified path does not exist. - public static Image? LoadImageFile(string file, Mode mode = Mode.Rgb) - { - if (!File.Exists(file)) - throw new FileNotFoundException(file); - - return mode switch - { - Mode.Rgb => new Image(DlibDotNet.Dlib.LoadImageAsMatrix(file), mode), - Mode.Greyscale => new Image(DlibDotNet.Dlib.LoadImageAsMatrix(file), mode), - _ => null, - }; - } - - #region Helpers - - private List RawFaceLandmarks(Image faceImage, int numberOfTimesToUpsample, IEnumerable? faceLocations, PredictorModel predictorModel, Model model) - { - IEnumerable locations; - - if (faceLocations == null) - { - List? list = new(); - IEnumerable? tmp = RawFaceLocations(faceImage, numberOfTimesToUpsample, model); - foreach (MModRect? mModRect in tmp) - { - list.Add(new Location(mModRect.DetectionConfidence, mModRect.Rect.Bottom, mModRect.Rect.Left, mModRect.Rect.Right, mModRect.Rect.Top, faceImage.Width, faceImage.Height)); - mModRect.Dispose(); - } - - locations = list; - } - else - { - locations = faceLocations; - } - - List results = new(); - if (predictorModel == PredictorModel.Custom) - { - if (CustomFaceLandmarkDetector is null) - throw new NullReferenceException(nameof(CustomFaceLandmarkDetector)); - foreach (Location? rect in locations) - { - FullObjectDetection? ret = CustomFaceLandmarkDetector.Detect(faceImage, rect); - results.Add(ret); - } - } - else - { - ShapePredictor? posePredictor = _PosePredictor68Point; - switch (predictorModel) - { - case PredictorModel.Small: - posePredictor = _PosePredictor5Point; - break; - } - - foreach (Location? rect in locations) - { - FullObjectDetection? ret = posePredictor.Detect(faceImage.Matrix, new DlibDotNet.Rectangle(rect.Left, rect.Top, rect.Right, rect.Bottom)); - results.Add(ret); - } - } - - return results; - } - - private IEnumerable RawFaceLocations(Image faceImage, int numberOfTimesToUpsample, Model model) - { - switch (model) - { - case Model.Custom: - if (CustomFaceDetector == null) - throw new NotSupportedException("The custom face detector is not ready."); - return CustomFaceDetector.Detect(faceImage, numberOfTimesToUpsample).Select(rect => new MModRect - { - Rect = new DlibDotNet.Rectangle(rect.Left, rect.Top, rect.Right, rect.Bottom), - DetectionConfidence = rect.Confidence - }); - case Model.Cnn: - return CnnFaceDetectionModelV1.Detect(_CnnFaceDetector, faceImage, numberOfTimesToUpsample); - default: - IEnumerable>? locations = SimpleObjectDetector.RunDetectorWithUpscale2(_FaceDetector, faceImage, (uint)numberOfTimesToUpsample); - return locations.Select(tuple => new MModRect { Rect = tuple.Item1, DetectionConfidence = tuple.Item2 }); - } - } - - private IEnumerable> RawFaceLocationsBatched(IEnumerable faceImages, int numberOfTimesToUpsample, int batchSize = 128) => CnnFaceDetectionModelV1.DetectMulti(_CnnFaceDetector, faceImages, numberOfTimesToUpsample, batchSize); - - private static Location TrimBound(DlibDotNet.Rectangle location, int width, int height) => new(Math.Max(location.Left, 0), Math.Max(location.Top, 0), Math.Min(location.Right, width), Math.Min(location.Bottom, height), width, height); - - #endregion - - #endregion - - #region Methods - - #region Overrides - - /// - /// Releases all unmanaged resources. - /// protected override void DisposeUnmanaged() { base.DisposeUnmanaged(); - _PosePredictor68Point?.Dispose(); _PosePredictor5Point?.Dispose(); _CnnFaceDetector?.Dispose(); @@ -830,8 +444,4 @@ public sealed class FaceRecognition : DisposableObject _FaceDetector?.Dispose(); } - #endregion - - #endregion - } \ No newline at end of file diff --git a/FaceRecognitionDotNet/FaceRecognitionDotNet.csproj b/FaceRecognitionDotNet/FaceRecognitionDotNet.csproj index 56da923..d7a5796 100644 --- a/FaceRecognitionDotNet/FaceRecognitionDotNet.csproj +++ b/FaceRecognitionDotNet/FaceRecognitionDotNet.csproj @@ -10,7 +10,7 @@ Phares.View.by.Distance.FaceRecognitionDotNet false - 5.0.402.104 + 6.0.100.1 Mike Phares Phares true diff --git a/Instance/DlibDotNet.cs b/Instance/DlibDotNet.cs index 7559321..b2f1c3f 100644 --- a/Instance/DlibDotNet.cs +++ b/Instance/DlibDotNet.cs @@ -26,14 +26,14 @@ public class DlibDotNet private readonly B_Metadata _Metadata; private readonly E_Distance _Distance; private readonly Serilog.ILogger? _Log; + private readonly D2_FaceParts _FaceParts; private readonly AppSettings _AppSettings; private readonly List _Exceptions; private readonly IsEnvironment _IsEnvironment; - private readonly D2_FaceLandmarks _FaceLandmarks; private readonly Models.Configuration _Configuration; private readonly bool _ArgZeroIsConfigurationRootDirectory; private readonly List> _FileKeyValuePairs; - private readonly Dictionary>> _FilePropertiesKeyValuePairs; + private readonly Dictionary>> _FilePropertiesKeyValuePairs; public DlibDotNet(List args, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console) { @@ -44,8 +44,8 @@ public class DlibDotNet _Exceptions = new List(); _Log = Serilog.Log.ForContext(); _FileKeyValuePairs = new List>(); - _FilePropertiesKeyValuePairs = new Dictionary>>(); - Property.Models.Configuration propertyConfiguration = Property.Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory); + _FilePropertiesKeyValuePairs = new Dictionary>>(); + Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot); _Log.Information(propertyConfiguration.RootDirectory); Property.Models.Configuration.Verify(propertyConfiguration); Models.Configuration configuration = Models.Binder.Configuration.Get(isEnvironment, configurationRoot, propertyConfiguration); @@ -57,7 +57,6 @@ public class DlibDotNet _People = new A2_People(configuration); _Rename = new E3_Rename(configuration); _Distance = new E_Distance(configuration); - _FaceLandmarks = new D2_FaceLandmarks(configuration); if (configuration.IgnoreExtensions is null) throw new NullReferenceException(nameof(configuration.IgnoreExtensions)); _Metadata = new(configuration.ForceMetadataLastWriteTimeToCreationTime, configuration.PropertiesChangedForMetadata); @@ -66,11 +65,8 @@ public class DlibDotNet else argZero = Path.GetFullPath(propertyConfiguration.RootDirectory); _ArgZeroIsConfigurationRootDirectory = propertyConfiguration.RootDirectory == argZero; - (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters) = C_Resize.GetTuple(configuration.OutputExtension, configuration.OutputQuality); - _Resize = new C_Resize(configuration.ForceResizeLastWriteTimeToCreationTime, configuration.OverrideForResizeImages, configuration.PropertiesChangedForResize, configuration.ValidResolutions, imageCodecInfo, encoderParameters); _Log.Information(configuration.ModelDirectory); (Model model, PredictorModel predictorModel, ModelParameter modelParameter) = GetModel(configuration); - _Faces = new D_Face(configuration, argZero, model, modelParameter, predictorModel); if (!_ArgZeroIsConfigurationRootDirectory) people = Array.Empty(); else @@ -81,6 +77,18 @@ public class DlibDotNet e2Navigate.Navigate(propertyConfiguration, model, predictorModel, configuration.OutputResolutions[0]); _Log.Information(propertyConfiguration.RootDirectory); } + { + (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) = C_Resize.GetGifLowQuality(); + _FaceParts = new D2_FaceParts(configuration, imageCodecInfo, encoderParameters, filenameExtension); + } + { + (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) = C_Resize.GetPngLowQuality(); + _Faces = new D_Face(configuration, argZero, model, modelParameter, predictorModel, imageCodecInfo, encoderParameters, filenameExtension); + } + { + (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) = C_Resize.GetTuple(configuration.OutputExtension, configuration.OutputQuality); + _Resize = new C_Resize(configuration.ForceResizeLastWriteTimeToCreationTime, configuration.OverrideForResizeImages, configuration.PropertiesChangedForResize, configuration.ValidResolutions, imageCodecInfo, encoderParameters, filenameExtension); + } if (!configuration.SkipSearch) Search(propertyConfiguration, configuration.Reverse, model, predictorModel, argZero, people, isSilent); if (_Exceptions.Count == 0 && _ArgZeroIsConfigurationRootDirectory) @@ -90,13 +98,13 @@ public class DlibDotNet foreach (string[] directoryCollection in directoryCollections) { _Log.Information(string.Concat("Cleaning <", directoryCollection[0], ">")); - _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(directoryCollection[0]); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(directoryCollection[0]); } - string d2FaceLandmarksRootDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(D2_FaceLandmarks)); - _Log.Information(string.Concat("Cleaning <", d2FaceLandmarksRootDirectory, ">")); - _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(d2FaceLandmarksRootDirectory); + string d2FacePartsRootDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(D2_FaceParts)); + _Log.Information(string.Concat("Cleaning <", d2FacePartsRootDirectory, ">")); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(d2FacePartsRootDirectory); if (appSettings.MaxDegreeOfParallelism < 2) - ticks = LogDelta(ticks, nameof(Property.Models.Stateless.IPath.DeleteEmptyDirectories)); + ticks = LogDelta(ticks, nameof(Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories)); } string message = $"There were {_Exceptions.Count} exception(s) thrown! {Environment.NewLine}{string.Join(Environment.NewLine, _Exceptions)}"; _Log.Information(message); @@ -112,7 +120,7 @@ public class DlibDotNet } } - private long LogDelta(long ticks, string methodName) + private long LogDelta(long ticks, string? methodName) { long result; if (_Log is null) @@ -245,16 +253,12 @@ public class DlibDotNet throw new Exception("Input directory should be the source and not a resized directory!"); } - private void FullParallelForWork(PropertyLogic propertyLogic, string outputResolution, string bResultsFullGroupDirectory, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, List> sourceDirectoryChanges, List propertyFileHolderCollection, List propertyCollection, List>> metadataCollections, List> resizeKeyValuePairs, List> imageFaceCollections, string sourceDirectory, int index, Item item) + private void FullParallelForWork(A_Property propertyLogic, string outputResolution, string bResultsFullGroupDirectory, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, List> sourceDirectoryChanges, List propertyFileHolderCollection, List propertyCollection, List>> metadataCollections, List> resizeKeyValuePairs, List> imageFaceCollections, string sourceDirectory, int index, Item item) { if (item.ImageFileHolder is null) throw new NullReferenceException(nameof(item.ImageFileHolder)); - if (_Configuration?.PropertyConfiguration is null) - throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration)); - if (_Configuration.PropertyConfiguration.WriteBitmapDataBytes is null) - throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration.WriteBitmapDataBytes)); - A_Property property; - List faceCollection; + Shared.Models.Property property; + List faceCollection; string original = "Original"; long ticks = DateTime.Now.Ticks; DateTime dateTime = DateTime.Now; @@ -282,7 +286,7 @@ public class DlibDotNet if (_AppSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(B_Metadata.GetMetadataCollection)); FileHolder resizedFileHolder = new(Path.Combine(_Resize.AngleBracketCollection[0].Replace("<>", "()"), Path.GetFileName(item.ImageFileHolder.FullName))); - item.SetResizedFileHolder(resizedFileHolder); + item.SetResizedFileHolder(_Resize.FilenameExtension, resizedFileHolder); imageResizeKeyValuePairs = _Resize.GetResizeKeyValuePairs(cResultsFullGroupDirectory, subFileTuples, parseExceptions, original, metadataCollection, item); if (_AppSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(C_Resize.GetResizeKeyValuePairs)); @@ -291,7 +295,7 @@ public class DlibDotNet _Resize.SaveResizedSubfile(outputResolution, cResultsFullGroupDirectory, subFileTuples, item, original, imageResizeKeyValuePairs); if (_AppSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(C_Resize.SaveResizedSubfile)); - item.SetResizedFileHolder(FileHolder.Refresh(resizedFileHolder)); + item.SetResizedFileHolder(_Resize.FilenameExtension, Shared.Models.Stateless.Methods.IFileHolder.Refresh(resizedFileHolder)); } else if (outputResolution == _Configuration.OutputResolutions[0] && false) { @@ -315,11 +319,14 @@ public class DlibDotNet _Faces.SaveFaces(dResultsFullGroupDirectory, subFileTuples, parseExceptions, item, faceCollection); if (_AppSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(D_Face.SaveFaces)); - if (_Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution)) + int?[] normalizedPixelPercentageCollection = Shared.Models.Stateless.Methods.IFace.GetInts(faceCollection); + int normalizedPixelPercentageDistinctCount = normalizedPixelPercentageCollection.Distinct().Count(); + if (normalizedPixelPercentageDistinctCount != normalizedPixelPercentageCollection.Length || _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution)) { - _FaceLandmarks.SaveFaceLandmarkImages(d2ResultsFullGroupDirectory, sourceDirectory, subFileTuples, parseExceptions, item, faceCollection); + bool saveRotated = _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution); + _FaceParts.SaveFaceLandmarkImages(d2ResultsFullGroupDirectory, sourceDirectory, subFileTuples, parseExceptions, item, faceCollection, saveRotated); if (_AppSettings.MaxDegreeOfParallelism < 2) - ticks = LogDelta(ticks, nameof(D2_FaceLandmarks.SaveFaceLandmarkImages)); + ticks = LogDelta(ticks, nameof(D2_FaceParts.SaveFaceLandmarkImages)); } } lock (sourceDirectoryChanges) @@ -333,7 +340,7 @@ public class DlibDotNet } } - private int FullParallelWork(long ticks, PropertyLogic propertyLogic, string outputResolution, string bResultsFullGroupDirectory, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, List> sourceDirectoryChanges, List propertyFileHolderCollection, List propertyCollection, List>> metadataCollection, List> resizeKeyValuePairs, List> faceCollections, int containersCount, Container container, Item[] filteredItems) + private int FullParallelWork(long ticks, A_Property propertyLogic, string outputResolution, string bResultsFullGroupDirectory, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, List> sourceDirectoryChanges, List propertyFileHolderCollection, List propertyCollection, List>> metadataCollection, List> resizeKeyValuePairs, List> faceCollections, int containersCount, Container container, Item[] filteredItems) { int result = 0; if (_Log is null) @@ -345,9 +352,9 @@ public class DlibDotNet for (int i = 0; i < filteredItems.Length; i++) { faceCollections.Add(new()); + propertyCollection.Add(null); metadataCollection.Add(new()); resizeKeyValuePairs.Add(new()); - propertyCollection.Add(new()); propertyFileHolderCollection.Add(null); } } @@ -401,7 +408,7 @@ public class DlibDotNet if (metadataIdLines.Any()) { text = string.Join(Environment.NewLine, from l in metadataIdLines orderby l.Id select l.Line); - _ = Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, text, updateDateWhenMatches: true, compareBeforeWrite: true); + _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, text, updateDateWhenMatches: true, compareBeforeWrite: true); } else { @@ -410,25 +417,23 @@ public class DlibDotNet } } - private void WriteGroup(Property.Models.Configuration configuration, PropertyLogic propertyLogic, List propertyCollection, List>> metadataCollection, List> faceCollections, List> resizeKeyValuePairs, string sourceDirectory, string outputResolution, Item[] filteredItems) + private void WriteGroup(Property.Models.Configuration configuration, A_Property propertyLogic, Shared.Models.Property[] propertyCollection, List>> metadataCollection, List> faceCollections, List> resizeKeyValuePairs, string sourceDirectory, string outputResolution, Item[] filteredItems) { - if (configuration.PropertiesChangedForProperty is null) - throw new NullReferenceException(nameof(configuration.PropertiesChangedForProperty)); Item item; string key; string json; string checkFile; int sourceDirectoryLength = sourceDirectory.Length; - _FilePropertiesKeyValuePairs.Add(sourceDirectory, new List>()); + _FilePropertiesKeyValuePairs.Add(sourceDirectory, new List>()); JsonSerializerOptions writeIndentedJsonSerializerOptions = new() { WriteIndented = false }; if (!(from l in propertyCollection where l?.Width is null select true).Any()) { string checkDirectory; - List>> faceCollectionsKeyValuePairs = new(); - List> propertyCollectionKeyValuePairs = new(); + List>> faceCollectionsKeyValuePairs = new(); + List> propertyCollectionKeyValuePairs = new(); List>> resizeKeyValuePairsCollections = new(); List>>> metadataCollectionKeyValuePairs = new(); - (int level, List directories) = Property.Models.Stateless.IPath.Get(configuration.RootDirectory, sourceDirectory); + (int level, List directories) = Shared.Models.Stateless.Methods.IPath.Get(configuration.RootDirectory, sourceDirectory); string fileName = string.Concat(string.Join(configuration.FileNameDirectorySeparator, directories), ".json"); for (int i = 0; i < filteredItems.Length; i++) { @@ -437,53 +442,53 @@ public class DlibDotNet continue; if (item.ImageFileHolder is null) continue; - key = Property.Models.Stateless.IPath.GetRelativePath(item.ImageFileHolder.FullName, sourceDirectoryLength); + key = Shared.Models.Stateless.Methods.IPath.GetRelativePath(item.ImageFileHolder.FullName, sourceDirectoryLength); _FileKeyValuePairs.Add(new KeyValuePair(sourceDirectory, key)); - _FilePropertiesKeyValuePairs[sourceDirectory].Add(new Tuple(key, propertyCollection[i])); - faceCollectionsKeyValuePairs.Add(new KeyValuePair>(key, faceCollections[i])); - propertyCollectionKeyValuePairs.Add(new KeyValuePair(key, propertyCollection[i])); + _FilePropertiesKeyValuePairs[sourceDirectory].Add(new Tuple(key, propertyCollection[i])); + faceCollectionsKeyValuePairs.Add(new KeyValuePair>(key, faceCollections[i])); + propertyCollectionKeyValuePairs.Add(new KeyValuePair(key, propertyCollection[i])); resizeKeyValuePairsCollections.Add(new KeyValuePair>(key, resizeKeyValuePairs[i])); metadataCollectionKeyValuePairs.Add(new KeyValuePair>>(key, metadataCollection[i])); } if (propertyLogic.AngleBracketCollection.Any()) { - checkDirectory = Property.Models.Stateless.IPath.GetDirectory(propertyLogic.AngleBracketCollection[0], level, "[{}]"); + checkDirectory = Shared.Models.Stateless.Methods.IPath.GetDirectory(propertyLogic.AngleBracketCollection[0], level, "[{}]"); checkFile = Path.Combine(checkDirectory, fileName); if (File.Exists(checkFile)) File.Move(checkFile, Path.Combine(checkDirectory, fileName)); checkFile = Path.Combine(checkDirectory, fileName); json = JsonSerializer.Serialize(propertyCollectionKeyValuePairs, writeIndentedJsonSerializerOptions); - _ = Property.Models.Stateless.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true); + _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true); } if (_Metadata.AngleBracketCollection.Any()) { - checkDirectory = Property.Models.Stateless.IPath.GetDirectory(_Metadata.AngleBracketCollection[0], level, "[{}]"); + checkDirectory = Shared.Models.Stateless.Methods.IPath.GetDirectory(_Metadata.AngleBracketCollection[0], level, "[{}]"); checkFile = Path.Combine(checkDirectory, fileName); if (File.Exists(checkFile)) File.Move(checkFile, Path.Combine(checkDirectory, fileName)); checkFile = Path.Combine(checkDirectory, fileName); json = JsonSerializer.Serialize(metadataCollectionKeyValuePairs, writeIndentedJsonSerializerOptions); - _ = Property.Models.Stateless.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true); + _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true); } if (_Resize.AngleBracketCollection.Any()) { - checkDirectory = Property.Models.Stateless.IPath.GetDirectory(_Resize.AngleBracketCollection[0], level, "[{}]"); + checkDirectory = Shared.Models.Stateless.Methods.IPath.GetDirectory(_Resize.AngleBracketCollection[0], level, "[{}]"); checkFile = Path.Combine(checkDirectory, fileName); if (File.Exists(checkFile)) File.Move(checkFile, Path.Combine(checkDirectory, fileName)); checkFile = Path.Combine(checkDirectory, fileName); json = JsonSerializer.Serialize(resizeKeyValuePairsCollections, writeIndentedJsonSerializerOptions); - _ = Property.Models.Stateless.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true); + _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true); } if (_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Contains(outputResolution) && _Faces.AngleBracketCollection.Any()) { - checkDirectory = Property.Models.Stateless.IPath.GetDirectory(_Faces.AngleBracketCollection[0], level, "[{}]"); + checkDirectory = Shared.Models.Stateless.Methods.IPath.GetDirectory(_Faces.AngleBracketCollection[0], level, "[{}]"); checkFile = Path.Combine(checkDirectory, fileName); if (File.Exists(checkFile)) File.Move(checkFile, Path.Combine(checkDirectory, fileName)); checkFile = Path.Combine(checkDirectory, fileName); json = JsonSerializer.Serialize(faceCollectionsKeyValuePairs, writeIndentedJsonSerializerOptions); - _ = Property.Models.Stateless.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true); + _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true); } } } @@ -499,7 +504,7 @@ public class DlibDotNet string dResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( configuration, model, predictorModel, nameof(D_Face), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true); string d2ResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( - configuration, model, predictorModel, nameof(D2_FaceLandmarks), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true); + configuration, model, predictorModel, nameof(D2_FaceParts), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true); string eResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( configuration, model, predictorModel, nameof(E_Distance), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true); string zResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( @@ -507,7 +512,7 @@ public class DlibDotNet return new(aResultsFullGroupDirectory, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, eResultsFullGroupDirectory, zResultsFullGroupDirectory); } - private void SetAngleBracketCollections(Property.Models.Configuration configuration, PropertyLogic propertyLogic, string outputResolution, Container container, string aResultsFullGroupDirectory, string bResultsFullGroupDirectory, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory) + private void SetAngleBracketCollections(Property.Models.Configuration configuration, A_Property propertyLogic, string outputResolution, Container container, string aResultsFullGroupDirectory, string bResultsFullGroupDirectory, string cResultsFullGroupDirectory, string dResultsFullGroupDirectory) { _Faces.AngleBracketCollection.Clear(); _Resize.AngleBracketCollection.Clear(); @@ -544,7 +549,7 @@ public class DlibDotNet converted: true)); } - private void FullDoWork(bool isSilent, string argZero, Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, long ticks, Dictionary> peopleCollection, PropertyLogic propertyLogic, List containers) + private void FullDoWork(string argZero, Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, long ticks, Map.Models.MapLogic mapLogic, A_Property propertyLogic, List containers) { if (_Log is null) throw new NullReferenceException(nameof(_Log)); @@ -559,11 +564,12 @@ public class DlibDotNet string eResultsFullGroupDirectory; string zResultsFullGroupDirectory; string d2ResultsFullGroupDirectory; - List> faceCollections = new(); - List propertyCollection = new(); + List> faceCollections = new(); + Shared.Models.Property[] propertyCollection; List propertyFileHolderCollection = new(); List> resizeKeyValuePairs = new(); List> sourceDirectoryChanges = new(); + List nullablePropertyCollection = new(); List>> metadataCollection = new(); string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}"); string propertyRoot = Property.Models.Stateless.IResult.GetResultsGroupDirectory(configuration, nameof(A_Property)); @@ -583,28 +589,29 @@ public class DlibDotNet continue; faceCollections.Clear(); metadataCollection.Clear(); - propertyCollection.Clear(); resizeKeyValuePairs.Clear(); sourceDirectoryChanges.Clear(); + nullablePropertyCollection.Clear(); propertyFileHolderCollection.Clear(); SetAngleBracketCollections(configuration, propertyLogic, outputResolution, container, aResultsFullGroupDirectory, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory); - exceptionCount = FullParallelWork(ticks, propertyLogic, outputResolution, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, sourceDirectoryChanges, propertyFileHolderCollection, propertyCollection, metadataCollection, resizeKeyValuePairs, faceCollections, containers.Count, container, filteredItems); + exceptionCount = FullParallelWork(ticks, propertyLogic, outputResolution, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, sourceDirectoryChanges, propertyFileHolderCollection, nullablePropertyCollection, metadataCollection, resizeKeyValuePairs, faceCollections, containers.Count, container, filteredItems); #pragma warning disable ids = (from l in filteredItems where l.Property?.Id is not null select l.Property.Id.Value).ToArray(); #pragma warning restore distinctCount = ids.Distinct().Count(); if (ids.Length != distinctCount) _Log.Information($"{ids.Length} != {distinctCount} <{container.SourceDirectory}>"); - if (metadataCollection.Count != filteredItems.Length || propertyCollection.Count != filteredItems.Length || resizeKeyValuePairs.Count != filteredItems.Length || faceCollections.Count != filteredItems.Length) + if (metadataCollection.Count != filteredItems.Length || nullablePropertyCollection.Count != filteredItems.Length || resizeKeyValuePairs.Count != filteredItems.Length || faceCollections.Count != filteredItems.Length) throw new Exception("Counts don't match!"); if (exceptionCount != 0) _Exceptions.Add(container.SourceDirectory); for (int i = 0; i < faceCollections.Count; i++) filteredItems[i].Faces.AddRange(from l in faceCollections[i] select l); + propertyCollection = (from l in nullablePropertyCollection where l is not null select l).ToArray(); if (_ArgZeroIsConfigurationRootDirectory && exceptionCount == 0) WriteGroup(configuration, propertyLogic, propertyCollection, metadataCollection, faceCollections, resizeKeyValuePairs, container.SourceDirectory, outputResolution, filteredItems); if (_ArgZeroIsConfigurationRootDirectory && exceptionCount == 0 && outputResolution == _Configuration.OutputResolutions[0]) - propertyLogic.AddToPropertyLogicAllCollection(filteredItems); + mapLogic.AddToMapLogicAllCollection(filteredItems); if (exceptionCount == 0 && _Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution)) _Distance.LoadOrCreateThenSaveDistanceResults(configuration, eResultsFullGroupDirectory, container.SourceDirectory, outputResolution, sourceDirectoryChanges, filteredItems); if (Directory.GetFiles(propertyRoot, "*.txt", SearchOption.TopDirectoryOnly).Any()) @@ -633,15 +640,6 @@ public class DlibDotNet } } - private PropertyLogic GetPropertyLogic(bool reverse, Model? model, PredictorModel? predictorModel) - { - PropertyLogic result; - if (_Configuration?.PropertyConfiguration is null) - throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration)); - result = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, reverse, model, predictorModel); - return result; - } - private void Search(Property.Models.Configuration configuration, bool reverse, Model? model, PredictorModel? predictorModel, string argZero, Person[] people, bool isSilent) { if (_Log is null) @@ -656,26 +654,27 @@ public class DlibDotNet string zResultsFullGroupDirectory; string d2ResultsFullGroupDirectory; Dictionary> peopleCollection = A2_People.Convert(people); - PropertyLogic propertyLogic = GetPropertyLogic(reverse, model, predictorModel); + Map.Models.MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration); + A_Property propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FilenameExtension, reverse, model, predictorModel, mapLogic.IndicesFromNew, mapLogic.KeyValuePairs); if (string.IsNullOrEmpty(configuration.RootDirectory)) - containers = Property.Models.Stateless.A_Property.Get(configuration, propertyLogic); + containers = A_Property.Get(configuration, propertyLogic); else containers = Property.Models.Stateless.Container.GetContainers(configuration, propertyLogic); - FullDoWork(isSilent, argZero, configuration, model, predictorModel, ticks, peopleCollection, propertyLogic, containers); + FullDoWork(argZero, configuration, model, predictorModel, ticks, mapLogic, propertyLogic, containers); foreach (string outputResolution in _Configuration.OutputResolutions) { (aResultsFullGroupDirectory, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, eResultsFullGroupDirectory, zResultsFullGroupDirectory) = GetResultsFullGroupDirectories(configuration, model, predictorModel, outputResolution); - if (_ArgZeroIsConfigurationRootDirectory && _Exceptions.Count == 0 && outputResolution == _Configuration.OutputResolutions[0] && (propertyLogic.NamedFaceInfoDeterministicHashCodeKeyValuePairs.Any() || propertyLogic.NamedDeterministicHashCodeKeyValuePairs.Any())) + if (_ArgZeroIsConfigurationRootDirectory && _Exceptions.Count == 0 && outputResolution == _Configuration.OutputResolutions[0] && (mapLogic.NamedFaceInfoDeterministicHashCodeKeyValuePairs.Any() || mapLogic.NamedDeterministicHashCodeKeyValuePairs.Any())) { - if (!string.IsNullOrEmpty(propertyLogic.DeterministicHashCodeRootDirectory) && !propertyLogic.IncorrectDeterministicHashCodeKeyValuePairs.Any()) - propertyLogic.UpdateKeyValuePairs(containers); + if (!string.IsNullOrEmpty(mapLogic.DeterministicHashCodeRootDirectory) && !mapLogic.IncorrectDeterministicHashCodeKeyValuePairs.Any()) + mapLogic.UpdateKeyValuePairs(containers); foreach (Container container in containers) { - Item.AddToNamed(propertyLogic, container.Items); + Map.Models.MapLogic.AddToNamed(mapLogic, container.Items); if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) - D_Face.SaveShortcuts(_Configuration.JuliePhares, dResultsFullGroupDirectory, ticks, peopleCollection, propertyLogic, container.Items); + D_Face.SaveShortcuts(_Configuration.JuliePhares, dResultsFullGroupDirectory, ticks, peopleCollection, mapLogic, container.Items); } - propertyLogic.SaveAllCollection(); + mapLogic.SaveAllCollection(); if (_Configuration.SaveResizedSubfiles) { string dFacesContentDirectory; @@ -687,13 +686,13 @@ public class DlibDotNet zPropertyHolderSingletonDirectory = Path.Combine(zResultsFullGroupDirectory, "{}"); eDistanceCollectionDirectory = Path.Combine(eResultsFullGroupDirectory, $"[{ticks}]"); List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> collection; - collection = E_Distance.ParallelWork(_AppSettings.MaxDegreeOfParallelism, argZero, propertyLogic, containers); + collection = E_Distance.ParallelWork(_AppSettings.MaxDegreeOfParallelism, argZero, mapLogic, containers); _ = LogDeltaInSeconds(ticks, nameof(E_Distance.ParallelWork)); E_Distance.SavePropertyHolders(argZero, containers, zPropertyHolderSingletonDirectory); _ = LogDeltaInSeconds(ticks, nameof(E_Distance.SavePropertyHolders)); E_Distance.SaveThreeSigmaFaceEncodings(collection, peopleCollection, eDistanceCollectionDirectory); _ = LogDeltaInSeconds(ticks, nameof(E_Distance.SaveThreeSigmaFaceEncodings)); - E_Distance.SaveClosest(argZero, containers, peopleCollection, eDistanceContentDirectory, dFacesContentDirectory); + E_Distance.SaveClosest(argZero, containers, peopleCollection, dFacesContentDirectory, d2ResultsFullGroupDirectory, eDistanceContentDirectory); _ = LogDeltaInMinutes(ticks, nameof(E_Distance.SaveClosest)); } if (!_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Any()) @@ -708,18 +707,18 @@ public class DlibDotNet identify.WriteAllText(configuration, _Configuration.OutputResolutions[0], identifiedCollection); if (_Configuration.LoadOrCreateThenSaveIndex && _FilePropertiesKeyValuePairs.Any()) _Index.SetIndex(configuration, model, predictorModel, _Configuration.OutputResolutions[0], _FilePropertiesKeyValuePairs); - } - _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(Path.Combine(aResultsFullGroupDirectory, "{}")); - _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(Path.Combine(bResultsFullGroupDirectory, "{}")); - _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(Path.Combine(cResultsFullGroupDirectory, "{}")); + } + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(aResultsFullGroupDirectory, "{}")); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(bResultsFullGroupDirectory, "{}")); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(cResultsFullGroupDirectory, "{}")); if (_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Contains(outputResolution)) - _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(Path.Combine(dResultsFullGroupDirectory, "[]")); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(dResultsFullGroupDirectory, "[]")); if (_Configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions.Contains(outputResolution)) - _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(Path.Combine(eResultsFullGroupDirectory, "[]")); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(eResultsFullGroupDirectory, "[]")); if (_Configuration.LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions.Contains(outputResolution)) - _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(Path.Combine(eResultsFullGroupDirectory, "[]")); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(eResultsFullGroupDirectory, "[]")); if (_Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution)) - _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(Path.Combine(d2ResultsFullGroupDirectory, "[]")); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(d2ResultsFullGroupDirectory, "[]")); } } diff --git a/Instance/Instance.csproj b/Instance/Instance.csproj index 074a1a9..6ef8809 100644 --- a/Instance/Instance.csproj +++ b/Instance/Instance.csproj @@ -10,7 +10,7 @@ Phares.View.by.Distance.Instance false - 5.0.402.104 + 6.0.100.1 Mike Phares Phares true @@ -53,12 +53,13 @@ - - - - + + + + + diff --git a/Instance/Models/_A2_People.cs b/Instance/Models/_A2_People.cs index 71cabfa..353d9b8 100644 --- a/Instance/Models/_A2_People.cs +++ b/Instance/Models/_A2_People.cs @@ -1,5 +1,4 @@ using System.Text.Json; -using View_by_Distance.Property.Models; using View_by_Distance.Shared.Models; namespace View_by_Distance.Instance.Models; @@ -37,7 +36,7 @@ internal class A2_People string directoryFullName; Dictionary> keyValuePairs = new(); string hPeopleCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A2_People), "[]"); - string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}"); + string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(Property.Models.A_Property), "{}"); foreach (G2_Identify identified in identifiedCollection) { fileInfo = new FileInfo(string.Concat(aPropertySingletonDirectory, identified.RelativePath)); @@ -56,7 +55,7 @@ internal class A2_People _ = Directory.CreateDirectory(directoryFullName); jsonFile = Path.Combine(directoryFullName, $"{segments[1]}.json"); json = JsonSerializer.Serialize(keyValuePair.Value, _WriteIndentedJsonSerializerOptions); - if (!Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches: true, compareBeforeWrite: true)) + if (!Shared.Models.Stateless.Methods.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches: true, compareBeforeWrite: true)) continue; } } @@ -64,8 +63,6 @@ internal class A2_People internal Person[] GetPeople(Property.Models.Configuration configuration) { Person[] results; - if (_Configuration?.PropertyConfiguration is null) - throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration)); string rootDirectory = _Configuration.PropertyConfiguration.RootDirectory; string peopleRootDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A2_People)); string? rootResultsDirectory = Path.GetDirectoryName(Path.GetDirectoryName(peopleRootDirectory)); diff --git a/Instance/Models/_D2_FaceLandmark.cs b/Instance/Models/_D2_FaceParts.cs similarity index 65% rename from Instance/Models/_D2_FaceLandmark.cs rename to Instance/Models/_D2_FaceParts.cs index cafc3f3..1d830db 100644 --- a/Instance/Models/_D2_FaceLandmark.cs +++ b/Instance/Models/_D2_FaceParts.cs @@ -1,8 +1,9 @@ using System.Drawing; +using System.Drawing.Imaging; using System.Text.Json; using View_by_Distance.Metadata.Models; -using View_by_Distance.Property.Models; using View_by_Distance.Resize.Models; +using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Properties; using View_by_Distance.Shared.Models.Stateless; @@ -11,16 +12,22 @@ namespace View_by_Distance.Instance.Models; /// // *.png /// -internal class D2_FaceLandmarks +internal class D2_FaceParts { private readonly Serilog.ILogger? _Log; + private readonly string _FilenameExtension; private readonly Configuration _Configuration; + private readonly ImageCodecInfo _ImageCodecInfo; + private readonly EncoderParameters _EncoderParameters; - internal D2_FaceLandmarks(Configuration configuration) + internal D2_FaceParts(Configuration configuration, ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) { _Configuration = configuration; - _Log = Serilog.Log.ForContext(); + _ImageCodecInfo = imageCodecInfo; + _EncoderParameters = encoderParameters; + _FilenameExtension = filenameExtension; + _Log = Serilog.Log.ForContext(); } public override string ToString() @@ -41,60 +48,64 @@ internal class D2_FaceLandmarks return result; } - private static void SaveFaceLandmarkImages(List faceCollections, List imageFiles, int pointSize, FileHolder resizedFileHolder) + private void SaveFaceParts(int pointSize, IFileHolder resizedFileHolder, bool saveRotated, List<(Face, string, string)> collection) { int x; int y; + double? α; int width; int height; - D_Face face; - string imageFileFullName; Bitmap rotated; - string rotatedImageFileFullName; - Shared.Models.FacePoint[] facePoints; - for (int i = 0; i < faceCollections.Count; i++) + foreach ((Face face, string fileName, string rotatedFileName) in collection) { - if (!faceCollections[i].Populated) + if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) continue; - face = faceCollections[i]; - imageFileFullName = imageFiles[i][0]; - rotatedImageFileFullName = imageFiles[i][1]; try { using (Image image = Image.FromFile(resizedFileHolder.FullName)) { using Graphics graphic = Graphics.FromImage(image); - if (face.FaceLandmarks is null || !face.FaceLandmarks.Any()) + if (face.FaceParts is null || !face.FaceParts.Any()) { + if (face.Location is null) + continue; width = face.Location.Right - face.Location.Left; height = face.Location.Bottom - face.Location.Top; graphic.DrawEllipse(Pens.Red, face.Location.Left, face.Location.Top, width, height); } else { - foreach (KeyValuePair keyValuePair in face.FaceLandmarks) + foreach ((FacePart facePart, FacePoint[] facePoints) in face.FaceParts) { - facePoints = keyValuePair.Value.ToArray(); - foreach (Shared.Models.FacePoint facePoint in facePoints) + foreach (FacePoint facePoint in facePoints) + { + if (face.Location is null) + continue; graphic.DrawEllipse(Pens.GreenYellow, face.Location.Left + facePoint.X - pointSize, face.Location.Top + facePoint.Y - pointSize, pointSize * 2, pointSize * 2); - if (keyValuePair.Key == FacePart.Chin.ToString()) + } + if (facePart == FacePart.Chin) continue; if (facePoints.Length < 3) continue; x = (int)(from l in facePoints select l.X).Average(); y = (int)(from l in facePoints select l.Y).Average(); + if (face.Location is null) + continue; graphic.DrawEllipse(Pens.Purple, face.Location.Left + x - pointSize, face.Location.Top + y - pointSize, pointSize * 2, pointSize * 2); } } - image.Save(imageFileFullName, System.Drawing.Imaging.ImageFormat.Png); + image.Save(fileName, _ImageCodecInfo, _EncoderParameters); } - if (face.α.HasValue) + if (saveRotated && face.FaceParts is not null) { + α = Shared.Models.Stateless.Methods.IFace.Getα(face.FaceParts); + if (α is null) + continue; using Image image = Image.FromFile(resizedFileHolder.FullName); - rotated = RotateBitmap(image, (float)face.α.Value); + rotated = RotateBitmap(image, (float)α.Value); if (rotated is not null) { - rotated.Save(rotatedImageFileFullName, System.Drawing.Imaging.ImageFormat.Png); + rotated.Save(rotatedFileName, _ImageCodecInfo, _EncoderParameters); rotated.Dispose(); } } @@ -105,10 +116,8 @@ internal class D2_FaceLandmarks #pragma warning restore CA1416 - internal void SaveFaceLandmarkImages(string d2ResultsFullGroupDirectory, string sourceDirectory, List> subFileTuples, List parseExceptions, Item item, List faceCollection) + internal void SaveFaceLandmarkImages(string d2ResultsFullGroupDirectory, string sourceDirectory, List> subFileTuples, List parseExceptions, Item item, List faceCollection, bool saveRotated) { - if (_Configuration.PropertyConfiguration is null) - throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration)); if (item.ImageFileHolder is null) throw new NullReferenceException(nameof(item.ImageFileHolder)); if (item.ResizedFileHolder is null) @@ -121,31 +130,31 @@ internal class D2_FaceLandmarks DateTime? dateTime = null; double deterministicHashCodeKey; long ticks = DateTime.Now.Ticks; - List imageFiles = new(); bool updateDateWhenMatches = false; List angleBracketCollection = new(); + List<(Face, string, string)> collection = new(); angleBracketCollection.AddRange(Property.Models.Stateless.IResult.GetDirectoryInfoCollection( _Configuration.PropertyConfiguration, sourceDirectory, d2ResultsFullGroupDirectory, - contentDescription: "n x 2 png file(s) for each face found", + contentDescription: "n x 2 gif file(s) for each face found", singletonDescription: string.Empty, collectionDescription: string.Empty, converted: false)); string facesDirectory = Path.Combine(angleBracketCollection[0].Replace("<>", "()"), item.ImageFileHolder.NameWithoutExtension); - string[] changesFrom = new string[] { nameof(A_Property), nameof(B_Metadata), nameof(C_Resize), nameof(D_Face) }; + string[] changesFrom = new string[] { nameof(Property.Models.A_Property), nameof(B_Metadata), nameof(C_Resize), nameof(D_Face) }; List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); if (!Directory.Exists(facesDirectory)) _ = Directory.CreateDirectory(facesDirectory); - foreach (IFace face in faceCollection) + foreach (Face face in faceCollection) { - if (!face.Populated || face.Location?.NormalizedPixelPercentage is null) + if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) { - imageFiles.Add(Array.Empty()); + collection.Add(new(face, string.Empty, string.Empty)); continue; } - deterministicHashCodeKey = Named.GetDeterministicHashCodeKey(item, face); - fileInfo = new FileInfo(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.png")); + deterministicHashCodeKey = Shared.Models.Stateless.Methods.INamed.GetDeterministicHashCodeKey(item, face); + fileInfo = new FileInfo(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FilenameExtension}")); if (!fileInfo.Exists) { if (fileInfo.Directory?.Parent is null) @@ -156,15 +165,15 @@ internal class D2_FaceLandmarks } if (string.IsNullOrEmpty(fileInfo.DirectoryName)) continue; - rotatedFileInfo = new FileInfo(Path.Combine(fileInfo.DirectoryName, $"{deterministicHashCodeKey} - R{item.ImageFileHolder.ExtensionLowered}")); - imageFiles.Add(new string[] { fileInfo.FullName, rotatedFileInfo.FullName }); + rotatedFileInfo = new FileInfo(Path.Combine(fileInfo.DirectoryName, $"{deterministicHashCodeKey} - R{item.ImageFileHolder.ExtensionLowered}{_FilenameExtension}")); + collection.Add(new(face, fileInfo.FullName, rotatedFileInfo.FullName)); if (check) continue; else if (_Configuration.OverrideForFaceLandmarkImages) check = true; else if (!fileInfo.Exists) check = true; - else if (!rotatedFileInfo.Exists) + else if (saveRotated && !rotatedFileInfo.Exists) check = true; else if (dateTimes.Any() && dateTimes.Max() > fileInfo.LastWriteTime) check = true; @@ -175,7 +184,7 @@ internal class D2_FaceLandmarks } } if (check) - SaveFaceLandmarkImages(faceCollection, imageFiles, pointSize, item.ResizedFileHolder); + SaveFaceParts(pointSize, item.ResizedFileHolder, saveRotated, collection); } } \ No newline at end of file diff --git a/Instance/Models/_D_Face.cs b/Instance/Models/_D_Face.cs index a196421..883b5c6 100644 --- a/Instance/Models/_D_Face.cs +++ b/Instance/Models/_D_Face.cs @@ -1,14 +1,13 @@ using System.Drawing; using System.Drawing.Drawing2D; +using System.Drawing.Imaging; using System.Text.Json; -using System.Text.Json.Serialization; using System.Text.RegularExpressions; using View_by_Distance.FaceRecognitionDotNet; using View_by_Distance.Metadata.Models; using View_by_Distance.Property.Models; using View_by_Distance.Resize.Models; using View_by_Distance.Shared.Models; -using View_by_Distance.Shared.Models.Properties; using View_by_Distance.Shared.Models.Stateless; using WindowsShortcutFactory; @@ -17,7 +16,7 @@ namespace View_by_Distance.Instance.Models; /// // List /// -public class D_Face : IFace, Shared.Models.Methods.IFace +public class D_Face { internal List AngleBracketCollection { get; } @@ -25,112 +24,29 @@ public class D_Face : IFace, Shared.Models.Methods.IFace private readonly Model _Model; private readonly string _ArgZero; private readonly Serilog.ILogger? _Log; + private readonly string _FilenameExtension; private readonly Configuration _Configuration; private readonly ModelParameter _ModelParameter; private readonly PredictorModel _PredictorModel; + private readonly ImageCodecInfo _ImageCodecInfo; + private readonly EncoderParameters _EncoderParameters; private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; - protected double? _Ī‘; - protected DateTime _DateTime; - protected Shared.Models.FaceEncoding _FaceEncoding; - protected Dictionary _FaceLandmarks; - protected Location _Location; - protected int? _LocationIndex; - protected OutputResolution _OutputResolution; - protected bool _Populated; - protected string _RelativePath; - public double? α => _Ī‘; - public DateTime DateTime => _DateTime; - public Shared.Models.FaceEncoding FaceEncoding => _FaceEncoding; - public Dictionary FaceLandmarks => _FaceLandmarks; - public OutputResolution OutputResolution => _OutputResolution; - public Location Location => _Location; - public int? LocationIndex => _LocationIndex; - public bool Populated => _Populated; - public string RelativePath => _RelativePath; - -#nullable disable - - [JsonConstructor] - public D_Face(double? α, DateTime dateTime, Shared.Models.FaceEncoding faceEncoding, Dictionary faceLandmarks, Location location, int? locationIndex, OutputResolution outputResolution, bool populated, string relativePath) - { - _Ī‘ = α; - _DateTime = dateTime; - _FaceEncoding = faceEncoding; - _FaceLandmarks = faceLandmarks; - _Location = location; - _LocationIndex = locationIndex; - _OutputResolution = outputResolution; - _Populated = populated; - _RelativePath = relativePath; - } - - internal D_Face(Configuration configuration, string argZero, Model model, ModelParameter modelParameter, PredictorModel predictorModel) + internal D_Face(Configuration configuration, string argZero, Model model, ModelParameter modelParameter, PredictorModel predictorModel, ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) { _Model = model; _ArgZero = argZero; _Configuration = configuration; _ModelParameter = modelParameter; _PredictorModel = predictorModel; + _ImageCodecInfo = imageCodecInfo; + _EncoderParameters = encoderParameters; + _FilenameExtension = filenameExtension; AngleBracketCollection = new List(); _Log = Serilog.Log.ForContext(); _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; } - private D_Face(Location location) - { - _Ī‘ = α; - _DateTime = DateTime.MinValue; - _FaceEncoding = null; - _FaceLandmarks = null; - _OutputResolution = null; - _Location = location; - _LocationIndex = null; - _Populated = false; - _RelativePath = string.Empty; - } - - private D_Face() - { - _Ī‘ = α; - _DateTime = DateTime.MinValue; - _FaceEncoding = null; - _FaceLandmarks = null; - _OutputResolution = null; - _Location = null; - _LocationIndex = null; - _Populated = false; - _RelativePath = string.Empty; - } - - private D_Face(A_Property property, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, string relativePath, int? i, Location location) - { - DateTime?[] dateTimes; - dateTimes = new DateTime?[] { property.CreationTime, property.LastWriteTime, property.DateTime, property.DateTimeDigitized, property.DateTimeOriginal, property.GPSDateStamp }; - _DateTime = (from l in dateTimes where l.HasValue select l.Value).Min(); - _FaceLandmarks = new Dictionary(); - _OutputResolution = new(outputResolutionHeight, outputResolutionOrientation, outputResolutionWidth); - _Location = location; - _LocationIndex = i; - _Populated = false; - _RelativePath = relativePath; - } - - private D_Face(int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, IFace face) - { - _Ī‘ = face.α; - _DateTime = face.DateTime; - _FaceEncoding = face.FaceEncoding; - _FaceLandmarks = face.FaceLandmarks; - _OutputResolution = new(outputResolutionHeight, outputResolutionOrientation, outputResolutionWidth); - _Location = face.Location; - _LocationIndex = face.LocationIndex; - _Populated = face.Populated; - _RelativePath = face.RelativePath; - } - -#nullable restore - private static void GetPointBounds(PointF[] points, out float xMinimum, out float xMaximum, out float yMinimum, out float yMaximum) { xMinimum = points[0].X; @@ -219,26 +135,22 @@ public class D_Face : IFace, Shared.Models.Methods.IFace return result; } - private static void SaveFaces(List faceCollection, FileHolder resizedFileHolder, List imageFiles) + private void SaveFaces(FileHolder resizedFileHolder, List<(Face, string)> collection) { int width; int height; Graphics graphics; - Location location; + Location? location; Bitmap preRotated; Rectangle rectangle; using Bitmap source = new(resizedFileHolder.FullName); - for (int i = 0; i < faceCollection.Count; i++) + foreach ((Face face, string fileName) in collection) { - if (!faceCollection[i].Populated || faceCollection[i]?.Location is null) + if (face.FaceEncoding is null || face?.Location is null) + continue; + location = Shared.Models.Stateless.Methods.ILocation.GetLocation(face.Location, source.Height, source.Width, collection.Count); + if (location is null) continue; - location = new Location(faceCollection[i].Location.Confidence, - faceCollection[i].Location.Bottom, - faceCollection[i].Location.Left, - faceCollection[i].Location.Right, - faceCollection[i].Location.Top, - source.Width, - source.Height); width = location.Right - location.Left; height = location.Bottom - location.Top; rectangle = new Rectangle(location.Left, location.Top, width, height); @@ -246,149 +158,54 @@ public class D_Face : IFace, Shared.Models.Methods.IFace { using (graphics = Graphics.FromImage(preRotated)) graphics.DrawImage(source, new Rectangle(0, 0, width, height), rectangle, GraphicsUnit.Pixel); - preRotated.Save(imageFiles[i], System.Drawing.Imaging.ImageFormat.Png); + preRotated.Save(fileName, _ImageCodecInfo, _EncoderParameters); } } } - private List GetFaces(FileHolder resizedFileHolder, Item item, A_Property property, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, string facesDirectory) + private List GetFaces(FileHolder resizedFileHolder, Item item, Shared.Models.Property property, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation) { - List results = new(); + List results = new(); if (item.ImageFileHolder is null) throw new NullReferenceException(nameof(item.ImageFileHolder)); - List locations; - FaceRecognitionDotNet.Image? unknownImage = null; - if (resizedFileHolder.Exists) + FaceRecognitionDotNet.Image? unknownImage; + if (!resizedFileHolder.Exists) + unknownImage = null; + else { try { unknownImage = FaceRecognition.LoadImageFile(resizedFileHolder.FullName); } - catch (Exception) { } + catch (Exception) + { unknownImage = null; } } if (unknownImage is null) - results.Add(new D_Face(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, item.RelativePath, i: null, location: null)); + results.Add(new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, item.RelativePath, i: null, location: null)); else { - FaceRecognition faceRecognition = FaceRecognition.Create(_ModelParameter); - locations = faceRecognition.FaceLocations(_Model, unknownImage, _Configuration.NumberOfTimesToUpsample, sortByNormalizedPixelPercentage: true); - if (!locations.Any()) - results.Add(new D_Face(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, item.RelativePath, i: null, location: null)); + List<(Location Location, FaceRecognitionDotNet.FaceEncoding? FaceEncoding, Dictionary? FaceParts)> collection; + FaceRecognition faceRecognition = new(_Configuration.NumberOfTimesToUpsample, _Configuration.NumberOfJitters, _PredictorModel, _Model, _ModelParameter); + collection = faceRecognition.GetCollection(unknownImage, includeFaceEncoding: true, includeFaceParts: true, sortByNormalizedPixelPercentage: true); + if (!collection.Any()) + results.Add(new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, item.RelativePath, i: null, location: null)); else { - double? α; - int width; - int height; - int padding; - int? leftEyeX; - int? leftEyeY; - int? rightEyeX; - int? rightEyeY; - Bitmap rotated; - string faceFile; - Location location; - Bitmap preRotated; - Graphics graphics; - D_Face? face = null; - Rectangle rectangle; + int i = 0; + Face face; double[] rawEncoding; - double deterministicHashCodeKey; - Shared.Models.FaceEncoding faceEncoding; - FaceRecognitionDotNet.Image? knownImage; - FaceRecognitionDotNet.Image? rotatedImage; - List<(FacePart, FacePoint[])[]> facesLandmarks; - List faceEncodings; - using Bitmap source = unknownImage.ToBitmap(); - padding = (int)((source.Width + source.Height) / 2 * .01); - for (int i = 0; i < locations.Count; i++) + Shared.Models.FaceEncoding convertedFaceEncoding; + foreach ((Location location, FaceRecognitionDotNet.FaceEncoding? faceEncoding, Dictionary? faceParts) in collection) { - for (int p = 0; p <= _Configuration.PaddingLoops; p++) + face = new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, item.RelativePath, i, location); + if (faceEncoding is not null) { - location = new(locations[i].Confidence, - locations[i].Bottom + (padding * p), - locations[i].Left - (padding * p), - locations[i].Right + (padding * p), - locations[i].Top - (padding * p), - source.Width, - source.Height); - face = new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, item.RelativePath, i, location); - width = location.Right - location.Left; - height = location.Bottom - location.Top; - rectangle = new Rectangle(location.Left, location.Top, width, height); - using (preRotated = new Bitmap(width, height)) - { - leftEyeX = null; - leftEyeY = null; - rightEyeX = null; - rightEyeY = null; - using (graphics = Graphics.FromImage(preRotated)) - graphics.DrawImage(source, new Rectangle(0, 0, width, height), rectangle, GraphicsUnit.Pixel); - // source.Save(Path.Combine(_Configuration.RootDirectory, "source.jpg")); - // preRotated.Save(Path.Combine(_Configuration.RootDirectory, $"{p} - preRotated.jpg")); - using (knownImage = FaceRecognition.LoadImage(preRotated)) - { - if (knownImage is null || knownImage.IsDisposed) - throw new NullReferenceException(nameof(knownImage)); - facesLandmarks = faceRecognition.GetFaceLandmarkCollection(knownImage, _Configuration.NumberOfTimesToUpsample, faceLocations: null, _PredictorModel, _Model); - } - if (facesLandmarks.Count == 0 && p < _Configuration.PaddingLoops) - continue; - else if (facesLandmarks.Count != 1) - continue; - foreach ((FacePart facePart, FacePoint[] facePoints) in facesLandmarks[0]) - { - face.FaceLandmarks.Add(facePart.ToString(), facePoints); - if (facePart is not FacePart.LeftEye and not FacePart.RightEye) - continue; - if (facePart is FacePart.LeftEye) - { - leftEyeX = (int)(from l in facePoints select l.X).Average(); - leftEyeY = (int)(from l in facePoints select l.Y).Average(); - } - if (facePart is FacePart.RightEye) - { - rightEyeX = (int)(from l in facePoints select l.X).Average(); - rightEyeY = (int)(from l in facePoints select l.Y).Average(); - } - } - if (rightEyeX is null || leftEyeX is null || rightEyeY is null || leftEyeY is null) - continue; - α = Shared.Models.Stateless.Methods.IFace.Getα(rightEyeX.Value, leftEyeX.Value, rightEyeY.Value, leftEyeY.Value); - using (rotated = RotateBitmap(preRotated, (float)α.Value)) - { - // rotated.Save(Path.Combine(_Configuration.RootDirectory, $"{p} - rotated.jpg")); - using (rotatedImage = FaceRecognition.LoadImage(rotated)) - { - if (rotatedImage is null || rotatedImage.IsDisposed) - throw new NullReferenceException(nameof(rotatedImage)); - faceEncodings = faceRecognition.FaceEncodings(rotatedImage, _Configuration.NumberOfTimesToUpsample, knownFaceLocation: null, _Configuration.NumberOfJitters, _PredictorModel, _Model); - } - if (faceEncodings.Count == 0 && p < _Configuration.PaddingLoops) - continue; - else if (faceEncodings.Count != 1) - continue; - rawEncoding = faceEncodings[0].GetRawEncoding(); - faceEncoding = new(rawEncoding, faceEncodings[0].Size); - face.Update(α, faceEncoding, populated: true); - } - deterministicHashCodeKey = Named.GetDeterministicHashCodeKey(item, face); - faceFile = Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.png"); - preRotated.Save(faceFile, System.Drawing.Imaging.ImageFormat.Png); - results.Add(face); - } - if (face.Populated) - break; - } - if (face is null || !face.Populated) - { - location = new(locations[i].Confidence, - locations[i].Bottom, - locations[i].Left, - locations[i].Right, - locations[i].Top, - source.Width, - source.Height); - face = new D_Face(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, item.RelativePath, i, location); - results.Add(face); + rawEncoding = faceEncoding.GetRawEncoding(); + convertedFaceEncoding = new(rawEncoding, faceEncoding.Size); + face.SetFaceEncoding(convertedFaceEncoding); } + if (faceParts is not null) + face.SetFaceParts(faceParts); + results.Add(face); + i += 1; } } unknownImage.Dispose(); @@ -401,16 +218,9 @@ public class D_Face : IFace, Shared.Models.Methods.IFace #pragma warning restore CA1416 - private void Update(double? α, Shared.Models.FaceEncoding faceEncoding, bool populated) + internal List GetFaces(string dResultsFullGroupDirectory, List> subFileTuples, List parseExceptions, Item item, Shared.Models.Property property, FileHolder resizedFileHolder, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation) { - _Ī‘ = α; - _FaceEncoding = faceEncoding; - _Populated = populated; - } - - internal List GetFaces(string dResultsFullGroupDirectory, List> subFileTuples, List parseExceptions, Item item, A_Property property, FileHolder resizedFileHolder, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation) - { - List? results; + List? results; if (item.Property?.Id is null) throw new NullReferenceException(nameof(item.Property.Id)); if (item.ImageFileHolder is null) @@ -418,9 +228,10 @@ public class D_Face : IFace, Shared.Models.Methods.IFace if (string.IsNullOrEmpty(dResultsFullGroupDirectory)) throw new NullReferenceException(nameof(dResultsFullGroupDirectory)); string json; + int?[] normalizedPixelPercentageCollection; + int normalizedPixelPercentageDistinctCount; string[] changesFrom = new string[] { nameof(A_Property), nameof(B_Metadata), nameof(C_Resize) }; List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); - string facesDirectory = Path.Combine(AngleBracketCollection[0].Replace("<>", "()"), item.ImageFileHolder.NameWithoutExtension); string usingRelativePath = Path.Combine(AngleBracketCollection[0].Replace("<>", "[]"), $"{item.ImageFileHolder.NameWithoutExtension}.json"); string dCollectionFile = Path.Combine(dResultsFullGroupDirectory, "[]", Property.Models.Stateless.IResult.AllInOne, $"{item.Property.Id.Value}{item.ImageFileHolder.ExtensionLowered}.json"); FileInfo fileInfo = new(dCollectionFile); @@ -443,8 +254,6 @@ public class D_Face : IFace, Shared.Models.Methods.IFace } } } - if (!Directory.Exists(facesDirectory)) - _ = Directory.CreateDirectory(facesDirectory); if (_Configuration.ForceFaceLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete"))) { File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName); @@ -466,9 +275,18 @@ public class D_Face : IFace, Shared.Models.Methods.IFace json = Shared.Models.Stateless.Methods.IFace.GetJson(fileInfo.FullName); try { - results = JsonSerializer.Deserialize>(json); + results = JsonSerializer.Deserialize>(json); if (results is null) throw new NullReferenceException(nameof(results)); + if (!_Configuration.ForceFaceLastWriteTimeToCreationTime) + { + normalizedPixelPercentageCollection = Shared.Models.Stateless.Methods.IFace.GetInts(results); + if (normalizedPixelPercentageCollection.Contains(3)) + throw new Exception($"Not allowed! <{fileInfo.FullName}>"); + normalizedPixelPercentageDistinctCount = normalizedPixelPercentageCollection.Distinct().Count(); + if (normalizedPixelPercentageDistinctCount != normalizedPixelPercentageCollection.Length) + throw new Exception($"Not distinct! <{fileInfo.FullName}>"); + } subFileTuples.Add(new Tuple(nameof(D_Face), fileInfo.LastWriteTime)); } catch (Exception) @@ -479,19 +297,24 @@ public class D_Face : IFace, Shared.Models.Methods.IFace } if (results is null) { - results = GetFaces(resizedFileHolder, item, property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, facesDirectory); + results = GetFaces(resizedFileHolder, item, property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation); json = JsonSerializer.Serialize(results, _WriteIndentedJsonSerializerOptions); bool updateDateWhenMatches = dateTimes.Any() && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime; DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max(); - if (Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime)) + if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime)) subFileTuples.Add(new Tuple(nameof(D_Face), DateTime.Now)); } if (_Configuration.ForceFaceLastWriteTimeToCreationTime) { + results = (from l in results select new Face(results.Count, l)).ToList(); + normalizedPixelPercentageCollection = Shared.Models.Stateless.Methods.IFace.GetInts(results); + normalizedPixelPercentageDistinctCount = normalizedPixelPercentageCollection.Distinct().Count(); + if (normalizedPixelPercentageDistinctCount != normalizedPixelPercentageCollection.Length) + throw new Exception($"Not distinct! <{fileInfo.FullName}>"); json = JsonSerializer.Serialize(results, _WriteIndentedJsonSerializerOptions); bool updateDateWhenMatches = dateTimes.Any() && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime; DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max(); - if (Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime)) + if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime)) { File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime); fileInfo.Refresh(); @@ -501,7 +324,7 @@ public class D_Face : IFace, Shared.Models.Methods.IFace return results; } - internal void SaveFaces(string dResultsFullGroupDirectory, List> subFileTuples, List parseExceptions, Item item, List faceCollection) + internal void SaveFaces(string dResultsFullGroupDirectory, List> subFileTuples, List parseExceptions, Item item, List faceCollection) { if (item.ImageFileHolder is null) throw new NullReferenceException(nameof(item.ImageFileHolder)); @@ -511,22 +334,22 @@ public class D_Face : IFace, Shared.Models.Methods.IFace bool check = false; string parentCheck; double deterministicHashCodeKey; - List imageFiles = new(); + List<(Face, string)> collection = new(); string[] changesFrom = new string[] { nameof(A_Property), nameof(B_Metadata), nameof(C_Resize) }; string facesDirectory = Path.Combine(AngleBracketCollection[0].Replace("<>", "()"), item.ImageFileHolder.NameWithoutExtension); List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); bool facesDirectoryExisted = Directory.Exists(facesDirectory); if (!facesDirectoryExisted) _ = Directory.CreateDirectory(facesDirectory); - foreach (IFace face in faceCollection) + foreach (Face face in faceCollection) { - if (!face.Populated || face.Location?.NormalizedPixelPercentage is null) + if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) { - imageFiles.Add(string.Empty); + collection.Add(new(face, string.Empty)); continue; } - deterministicHashCodeKey = Named.GetDeterministicHashCodeKey(item, face); - fileInfo = new FileInfo(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.png")); + deterministicHashCodeKey = Shared.Models.Stateless.Methods.INamed.GetDeterministicHashCodeKey(item, face); + fileInfo = new FileInfo(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FilenameExtension}")); if (!fileInfo.Exists) { if (fileInfo.Directory?.Parent is null) @@ -535,7 +358,7 @@ public class D_Face : IFace, Shared.Models.Methods.IFace if (File.Exists(parentCheck)) File.Delete(parentCheck); } - imageFiles.Add(fileInfo.FullName); + collection.Add(new(face, fileInfo.FullName)); if (_Configuration.OverrideForFaceImages) check = true; else if (!fileInfo.Exists) @@ -544,10 +367,10 @@ public class D_Face : IFace, Shared.Models.Methods.IFace check = true; } if (check) - SaveFaces(faceCollection, item.ResizedFileHolder, imageFiles); + SaveFaces(item.ResizedFileHolder, collection); } - internal static void SaveShortcuts(string[] juliePhares, string dResultsFullGroupDirectory, long ticks, Dictionary> peopleCollection, PropertyLogic propertyLogic, List items) + internal static void SaveShortcuts(string[] juliePhares, string dResultsFullGroupDirectory, long ticks, Dictionary> peopleCollection, Map.Models.MapLogic mapLogic, List items) { Person person; string fileName; @@ -556,18 +379,18 @@ public class D_Face : IFace, Shared.Models.Methods.IFace WindowsShortcut windowsShortcut; const string pattern = @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]"; string dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, $"({ticks})"); - List<(Item, (string, IFace?, (string, string, string, string))[])> collections = Item.GetCollection(propertyLogic, items, dFacesContentDirectory); - foreach ((Item item, (string personKey, IFace? _, (string, string, string, string))[] collection) in collections) + List<(Item, (string, Face?, (string, string, string, string))[])> collections = Map.Models.MapLogic.GetCollection(mapLogic, items, dFacesContentDirectory); + foreach ((Item item, (string personKey, Face? _, (string, string, string, string))[] collection) in collections) { if (collection.Length != 1) continue; - foreach ((string personKey, IFace? _, (string directory, string copyDirectory, string copyFileName, string shortcutFileName)) in collection) + foreach ((string personKey, Face? _, (string directory, string copyDirectory, string copyFileName, string shortcutFileName)) in collection) { if (string.IsNullOrEmpty(personKey)) continue; if (item.Property?.Id is null || item.ImageFileHolder is null || item.ResizedFileHolder is null) continue; - minimumDateTime = Property.Models.Stateless.A_Property.GetMinimumDateTime(item.Property); + minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property); if (minimumDateTime is null) continue; if (!Directory.Exists(directory)) @@ -601,24 +424,16 @@ public class D_Face : IFace, Shared.Models.Methods.IFace } } - double Shared.Models.Stateless.Methods.IFace.TestStatic_Getα(int x1, int x2, int y1, int y2) => throw new NotImplementedException(); - - string Shared.Models.Stateless.Methods.IFace.TestStatic_GetJson(string jsonFileFullName) => throw new NotImplementedException(); - - Face Shared.Models.Stateless.Methods.IFace.TestStatic_GetFace(string jsonFileFullName) => throw new NotImplementedException(); - - Face[] Shared.Models.Stateless.Methods.IFace.TestStatic_GetFaces(string jsonFileFullName) => throw new NotImplementedException(); - - private static bool HasLeftAndRight(Dictionary faceLandmarks) + private static bool HasLeftAndRight(Dictionary faceParts) { bool result = true; - if (!faceLandmarks.ContainsKey(FacePart.LeftEye.ToString())) + if (!faceParts.ContainsKey(FacePart.LeftEye.ToString())) result = false; - else if (!faceLandmarks.ContainsKey(FacePart.RightEye.ToString())) + else if (!faceParts.ContainsKey(FacePart.RightEye.ToString())) result = false; - else if (!faceLandmarks.ContainsKey(FacePart.LeftEyebrow.ToString())) + else if (!faceParts.ContainsKey(FacePart.LeftEyebrow.ToString())) result = false; - else if (!faceLandmarks.ContainsKey(FacePart.RightEyebrow.ToString())) + else if (!faceParts.ContainsKey(FacePart.RightEyebrow.ToString())) result = false; return result; } diff --git a/Instance/Models/_E2_Navigate.cs b/Instance/Models/_E2_Navigate.cs index 4c33b79..b07abff 100644 --- a/Instance/Models/_E2_Navigate.cs +++ b/Instance/Models/_E2_Navigate.cs @@ -96,8 +96,6 @@ internal class E2_Navigate string result; if (_Log is null) throw new NullReferenceException(nameof(_Log)); - if (_Configuration?.PropertyConfiguration is null) - throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration)); _Log.Warn(string.Concat("What is the new name for [", Path.GetFileName(subSourceDirectory), "]<", subSourceDirectory, ">?")); string? newDirectoryName = _Console.ReadLine(); _Log.Warn("Are you sure y[es] || n[o]?"); @@ -111,7 +109,7 @@ internal class E2_Navigate { _Log.Warn(string.Empty); string eDistanceCollectionDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(E_Distance), _Configuration.ValidResolutions[0], includeResizeGroup: true, includeModel: true, includePredictorModel: true), "[]"); - string relativePath = Property.Models.Stateless.IPath.GetRelativePath(subSourceDirectory, eDistanceCollectionDirectory.Length); + string relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(subSourceDirectory, eDistanceCollectionDirectory.Length); if (relativePath.Length == 1) throw new Exception(); if (Directory.Exists(Path.Combine(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName))) diff --git a/Instance/Models/_E3_Rename.cs b/Instance/Models/_E3_Rename.cs index b79db59..1fa7923 100644 --- a/Instance/Models/_E3_Rename.cs +++ b/Instance/Models/_E3_Rename.cs @@ -1,6 +1,5 @@ using System.Text.Json; using View_by_Distance.Metadata.Models; -using View_by_Distance.Property.Models; using View_by_Distance.Resize.Models; using View_by_Distance.Shared.Models.Stateless; @@ -40,10 +39,10 @@ internal class E3_Rename string cResizeSingletonDirectory; string eDistanceContentDirectory; string aPropertySingletonDirectory; + string d2FacePartsContentDirectory; string bMetadataSingletonDirectory; string eDistanceCollectionDirectory; string g2IdentifyCollectionDirectory; - string d2FaceLandmarksContentDirectory; add = Directory.Exists(string.Concat(Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(C_Resize), _Configuration.ValidResolutions[0], includeResizeGroup: true, includeModel: false, includePredictorModel: false), "()"), relativePath)); bMetadataSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(B_Metadata), "{}"); if (Directory.Exists(bMetadataSingletonDirectory)) @@ -51,7 +50,7 @@ internal class E3_Rename to = Path.Combine(string.Concat(bMetadataSingletonDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); results.Add(to); } - aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}"); + aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(Property.Models.A_Property), "{}"); if (Directory.Exists(aPropertySingletonDirectory)) { to = Path.Combine(string.Concat(aPropertySingletonDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); @@ -83,10 +82,10 @@ internal class E3_Rename to = Path.Combine(string.Concat(dFacesCollectionDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); results.Add(to); } - d2FaceLandmarksContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(D2_FaceLandmarks), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "()"); - if (add && _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution) && Directory.Exists(d2FaceLandmarksContentDirectory)) + d2FacePartsContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(D2_FaceParts), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "()"); + if (add && _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution) && Directory.Exists(d2FacePartsContentDirectory)) { - to = Path.Combine(string.Concat(d2FaceLandmarksContentDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + to = Path.Combine(string.Concat(d2FacePartsContentDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); results.Add(to); } eDistanceContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(E_Distance), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "()"); @@ -114,8 +113,6 @@ internal class E3_Rename internal List GetDirectoryRenameCollections(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string relativePath, string newDirectoryName, bool jsonFiles4InfoAny) { List results = new(); - if (_Configuration?.PropertyConfiguration is null) - throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration)); bool add; string to; bool exists; @@ -127,9 +124,9 @@ internal class E3_Rename string eDistanceContentDirectory; string bMetadataSingletonDirectory; string aPropertySingletonDirectory; + string d2FacePartsContentDirectory; string eDistanceCollectionDirectory; string g2IdentifyCollectionDirectory; - string d2FaceLandmarksContentDirectory; if (!string.IsNullOrEmpty(relativePath)) { from = string.Concat(_Configuration.PropertyConfiguration.RootDirectory, relativePath); @@ -147,7 +144,7 @@ internal class E3_Rename to = Path.Combine(string.Concat(bMetadataSingletonDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); results.Add(new string[] { from, to }); } - aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}"); + aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(Property.Models.A_Property), "{}"); from = string.Concat(aPropertySingletonDirectory, relativePath); exists = Directory.Exists(aPropertySingletonDirectory); if (exists) @@ -187,14 +184,14 @@ internal class E3_Rename to = Path.Combine(string.Concat(dFacesCollectionDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); results.Add(new string[] { from, to }); } - d2FaceLandmarksContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(D2_FaceLandmarks), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "()"); - from = string.Concat(d2FaceLandmarksContentDirectory, relativePath); - exists = Directory.Exists(d2FaceLandmarksContentDirectory); + d2FacePartsContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(D2_FaceParts), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "()"); + from = string.Concat(d2FacePartsContentDirectory, relativePath); + exists = Directory.Exists(d2FacePartsContentDirectory); if (!exists && add && _Configuration.SaveFaceLandmarkForOutputResolutions.Contains(outputResolution)) results.Add(new string[] { from }); else if (exists) { - to = Path.Combine(string.Concat(d2FaceLandmarksContentDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); + to = Path.Combine(string.Concat(d2FacePartsContentDirectory, Path.GetDirectoryName(relativePath)), newDirectoryName); results.Add(new string[] { from, to }); } eDistanceContentDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(E_Distance), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "()"); @@ -229,15 +226,13 @@ internal class E3_Rename internal void DirectoryRename(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string relativePath, string newDirectoryName) { - if (_Configuration?.PropertyConfiguration is null) - throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration)); string json; FileInfo current; FileInfo fileInfo; string error = "Error"; string target = "Target"; string pending = "Pending"; - System.IO.DirectoryInfo directoryInfo; + DirectoryInfo directoryInfo; IEnumerator fileInfoCollection; string oldValue = string.Concat("\"", relativePath); string oldDirectoryName = Path.GetFileName(relativePath); @@ -249,7 +244,7 @@ internal class E3_Rename string newValue = string.Concat("\"", Path.Combine(relativePathParent, newDirectoryName)); string e3RenameContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(E3_Rename), "()"); string jsonRootDirectory = Path.Combine(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, " - Copied"), string.Concat(directoryName, " - 4) Info"), _Configuration.PropertyConfiguration.DateGroup, "[]"); - directoryInfo = new System.IO.DirectoryInfo(jsonRootDirectory); + directoryInfo = new DirectoryInfo(jsonRootDirectory); if (!directoryInfo.Exists) directoryInfo.Create(); IEnumerator fileInfoCollection4 = directoryInfo.EnumerateFiles("*.json", SearchOption.AllDirectories).GetEnumerator(); @@ -278,7 +273,7 @@ internal class E3_Rename { foreach (string[] directoryCollection in directoryCollections) { - directoryInfo = new System.IO.DirectoryInfo(directoryCollection[0]); + directoryInfo = new DirectoryInfo(directoryCollection[0]); if (!directoryInfo.Exists) continue; fileInfoCollection = directoryInfo.EnumerateFiles("*.json", SearchOption.AllDirectories).GetEnumerator(); @@ -299,7 +294,7 @@ internal class E3_Rename if (json.Contains(oldValue)) { json = json.Replace(oldValue, newValue); - if (!Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true)) + if (!Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true)) continue; File.SetLastWriteTime(fileInfo.FullName, fileInfo.LastWriteTime); } diff --git a/Instance/Models/_E_Distance.cs b/Instance/Models/_E_Distance.cs index c02127c..dd930bb 100644 --- a/Instance/Models/_E_Distance.cs +++ b/Instance/Models/_E_Distance.cs @@ -4,6 +4,7 @@ using View_by_Distance.FaceRecognitionDotNet; using View_by_Distance.Metadata.Models; using View_by_Distance.Property.Models; using View_by_Distance.Resize.Models; +using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Properties; using View_by_Distance.Shared.Models.Stateless; using WindowsShortcutFactory; @@ -30,14 +31,14 @@ internal class E_Distance return result; } - private static List GetDistanceHolder(Item[] items, List<(string JSONDirectory, string TSVDirectory)> directories) + private static List<(DistanceHolder, FaceRecognitionDotNet.FaceEncoding?)> GetDistanceHolder(Item[] items, List<(string JSONDirectory, string TSVDirectory)> directories) { - List results = new(); + List<(DistanceHolder, FaceRecognitionDotNet.FaceEncoding?)> results = new(); Item item; const int zero = 0; string tsvDirectory; string jsonDirectory; - FaceEncoding? faceEncoding; + FaceRecognitionDotNet.FaceEncoding? faceEncoding; if (items.Length != directories.Count) throw new Exception(); for (int i = 0; i < items.Length; i++) @@ -48,38 +49,19 @@ internal class E_Distance continue; tsvDirectory = directories[i].TSVDirectory; jsonDirectory = directories[i].JSONDirectory; - foreach (IFace face in item.Faces) + foreach (Face face in item.Faces) { - if (!face.Populated) + if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) continue; faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding); - results.Add(new(face, faceEncoding, item.ImageFileHolder, item.Property.Id.Value, jsonDirectory, item.Faces[zero].Location, tsvDirectory)); + results.Add(new(new(face, item.ImageFileHolder, item.Property.Id.Value, jsonDirectory, item.Faces[zero].Location, tsvDirectory), faceEncoding)); } if (faceEncoding is null) - results.Add(new(item.Faces[zero], null, item.ImageFileHolder, item.Property.Id.Value, jsonDirectory, item.Faces[zero].Location, tsvDirectory)); + results.Add(new(new(item.Faces[zero], item.ImageFileHolder, item.Property.Id.Value, jsonDirectory, item.Faces[zero].Location, tsvDirectory), null)); } return results; } - private List> GetOrderedNoFaceCollection(List> faceCollections, int i, IFace face) - { - List> results = new() { new(face, string.Empty) }; - for (int n = 0; n < faceCollections.Count; n++) - { - if (i == n) - continue; - for (int j = 0; j < faceCollections[n].Count; j++) - { - if (!faceCollections[n][j].Populated) - continue; - results.Add(new(faceCollections[n][j], string.Empty)); - } - } - for (int r = results.Count - 1; r > _Configuration.MaxItemsInDistanceCollection; r--) - results.RemoveAt(r); - return results; - } - private void WriteNoFaceCollection(bool updateDateWhenMatches, DateTime? updateToWhenMatches, List> subFileTuples, List distanceHolders) { string json; @@ -87,7 +69,7 @@ internal class E_Distance string jsonFile; const int zero = 0; DistanceHolder distanceHolder; - List> tupleCollection; + List> tupleCollection; for (int i = 0; i < distanceHolders.Count; i++) { distanceHolder = distanceHolders[i]; @@ -108,24 +90,24 @@ internal class E_Distance break; } json = JsonSerializer.Serialize(tupleCollection, _WriteIndentedJsonSerializerOptions); - if (Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: updateToWhenMatches)) + if (Shared.Models.Stateless.Methods.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: updateToWhenMatches)) subFileTuples.Add(new Tuple(nameof(E_Distance), DateTime.Now)); } } - private static List GetFaceEncodings(List distanceHolders) + private static List GetFaceEncodings((DistanceHolder, FaceRecognitionDotNet.FaceEncoding?)[] distanceHoldersAfterSort) { - List results = new(); - foreach (DistanceHolder distanceHolder in distanceHolders) + List results = new(); + foreach ((DistanceHolder distanceHolder, FaceRecognitionDotNet.FaceEncoding? faceEncoding) in distanceHoldersAfterSort) { - if (!distanceHolder.Face.Populated || distanceHolder.FaceEncoding is null) + if (distanceHolder.Face.FaceEncoding is null || distanceHolder.Face.Location?.NormalizedPixelPercentage is null || faceEncoding is null) continue; - results.Add(distanceHolder.FaceEncoding); + results.Add(faceEncoding); } return results; } - private void SaveDistanceResults(bool updateDateWhenMatches, DateTime? updateToWhenMatches, List> subFileTuples, List distanceHolders) + private void SaveDistanceResults(bool updateDateWhenMatches, DateTime? updateToWhenMatches, List> subFileTuples, List<(DistanceHolder DistanceHolder, FaceRecognitionDotNet.FaceEncoding? _)> distanceHolders) { string json; string check; @@ -135,13 +117,16 @@ internal class E_Distance DistanceHolder distanceHolder; int normalizedPixelPercentage; DistanceHolder[] sortedDistanceHolders; - List> tupleCollection; + List> tupleCollection; List<(int Index, double Distance)> collection; - distanceHolders = distanceHolders.OrderByDescending(l => l.Face.Populated).ToList(); - List faceEncodings = GetFaceEncodings(distanceHolders); - for (int i = 0; i < distanceHolders.Count; i++) + FaceRecognitionDotNet.FaceEncoding? faceEncoding; + (DistanceHolder DistanceHolder, FaceRecognitionDotNet.FaceEncoding? FaceEncoding)[] distanceHoldersAfterSort = + distanceHolders.OrderByDescending(l => l.DistanceHolder.Face.FaceEncoding is not null && l.DistanceHolder.Face.Location?.NormalizedPixelPercentage is not null).ToArray(); + List faceEncodings = GetFaceEncodings(distanceHoldersAfterSort); + for (int i = 0; i < distanceHoldersAfterSort.Length; i++) { - distanceHolder = distanceHolders[i]; + faceEncoding = distanceHoldersAfterSort[i].FaceEncoding; + distanceHolder = distanceHoldersAfterSort[i].DistanceHolder; collection = new(); tupleCollection = new(); distanceHolder.Sort = 0d; @@ -149,7 +134,7 @@ internal class E_Distance locationIndex = 0; else locationIndex = distanceHolder.Face.LocationIndex.Value; - if (!distanceHolder.Face.Populated || distanceHolder.Face.Location?.NormalizedPixelPercentage is null) + if (distanceHolder.Face.FaceEncoding is null || distanceHolder.Face.Location?.NormalizedPixelPercentage is null) normalizedPixelPercentage = 0; else normalizedPixelPercentage = distanceHolder.Face.Location.NormalizedPixelPercentage.Value; @@ -161,27 +146,32 @@ internal class E_Distance File.Move(check, jsonFile); if (faceEncodings.Count == 1) faceDistances = new() { 0d }; - else if (distanceHolder.FaceEncoding is null) + else if (faceEncoding is null) faceDistances = Enumerable.Repeat(9d, faceEncodings.Count).ToList(); else - faceDistances = FaceRecognition.FaceDistances(faceEncodings, distanceHolder.FaceEncoding); - if (distanceHolder.Face.Populated && distanceHolder.FaceEncoding is not null && faceDistances[i] != 0d) + faceDistances = FaceRecognition.FaceDistances(faceEncodings, faceEncoding); + if (distanceHolder.Face.FaceEncoding is not null && faceEncoding is not null && faceDistances[i] != 0d) faceDistances[i] = 0d; for (int d = 0; d < faceDistances.Count; d++) collection.Add(new(d, faceDistances[d])); collection = collection.OrderBy(l => l.Distance).ToList(); foreach ((int index, double distance) in collection) - distanceHolders[index].Sort = ((distance * _Configuration.DistanceFactor) + (distanceHolders[index].Location.Confidence * _Configuration.LocationConfidenceFactor)) / 10; - sortedDistanceHolders = distanceHolders.OrderBy(l => l.Sort).ToArray(); + { + distanceHolder = distanceHoldersAfterSort[index].DistanceHolder; + if (distanceHolder.Location is null) + continue; + distanceHolder.Sort = ((distance * _Configuration.DistanceFactor) + (distanceHolder.Location.Confidence * _Configuration.LocationConfidenceFactor)) / 10; + } + sortedDistanceHolders = (from l in distanceHoldersAfterSort orderby l.DistanceHolder.Sort select l.DistanceHolder).ToArray(); for (int j = 0; j < sortedDistanceHolders.Length; j++) { distanceHolder = sortedDistanceHolders[j]; - tupleCollection.Add(new(distanceHolders[j].Face, string.Empty)); + tupleCollection.Add(new(distanceHoldersAfterSort[j].DistanceHolder.Face, string.Empty)); if (tupleCollection.Count > _Configuration.MaxItemsInDistanceCollection) break; } json = JsonSerializer.Serialize(tupleCollection, _WriteIndentedJsonSerializerOptions); - if (Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: updateToWhenMatches)) + if (Shared.Models.Stateless.Methods.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: updateToWhenMatches)) subFileTuples.Add(new Tuple(nameof(E_Distance), DateTime.Now)); } } @@ -196,10 +186,12 @@ internal class E_Distance string usingRelativePath; DateTime? dateTime = null; string dCollectionDirectory; + FileInfo[] fileInfoCollection; bool updateDateWhenMatches = false; System.IO.DirectoryInfo directoryInfo; System.IO.DirectoryInfo tvsDirectoryInfo; - IEnumerator fileInfoCollection; + int?[] normalizedPixelPercentageCollection; + int normalizedPixelPercentageDistinctCount; List<(string, string)> directories = new(); string[] changesFrom = new string[] { nameof(A_Property), nameof(B_Metadata), nameof(C_Resize), nameof(D_Face) }; List dateTimes = (from l in sourceDirectoryChanges where changesFrom.Contains(l.Item1) select l.Item2).ToList(); @@ -216,7 +208,7 @@ internal class E_Distance item = filteredItems[i]; if (item.ImageFileHolder is null || item.Property?.Id is null) continue; - hasPopulatedFace = (from l in item.Faces where l.Populated select true).Any(); + hasPopulatedFace = (from l in item.Faces where l.FaceEncoding is not null && l.Location?.NormalizedPixelPercentage is not null select true).Any(); usingRelativePath = Path.Combine(directoryInfoCollection[0].Replace("<>", "[]"), item.ImageFileHolder.NameWithoutExtension); dCollectionDirectory = Path.Combine(eResultsFullGroupDirectory, "[]", Property.Models.Stateless.IResult.AllInOne, $"{item.Property.Id.Value}{item.ImageFileHolder.ExtensionLowered}"); directoryInfo = new System.IO.DirectoryInfo(dCollectionDirectory); @@ -242,23 +234,30 @@ internal class E_Distance } tvsDirectoryInfo = new System.IO.DirectoryInfo(Path.Combine(directoryInfoCollection[0].Replace("<>", "()"), item.ImageFileHolder.NameWithoutExtension)); directories.Add(new(directoryInfo.FullName, tvsDirectoryInfo.FullName)); - if (_Configuration.CheckJsonForDistanceResults && directoryInfo.Exists) + if (directoryInfo.Exists && (!check || _Configuration.CheckJsonForDistanceResults)) { json = string.Empty; - fileInfoCollection = directoryInfo.EnumerateFiles("*.json", SearchOption.AllDirectories).GetEnumerator(); - for (int j = 0; j < int.MaxValue; j++) - { - if (!fileInfoCollection.MoveNext()) - break; - json = Shared.Models.Stateless.Methods.IIndex.GetJson(fileInfoCollection.Current.FullName, fileInfoCollection.Current); - if (!_Configuration.PropertiesChangedForDistance && Shared.Models.Stateless.Methods.IFace.GetFace(fileInfoCollection.Current.FullName) is null) - { - check = true; - break; - } - } - if (!check && string.IsNullOrEmpty(json)) + normalizedPixelPercentageCollection = Shared.Models.Stateless.Methods.IFace.GetInts(item.Faces); + normalizedPixelPercentageDistinctCount = normalizedPixelPercentageCollection.Distinct().Count(); + if (normalizedPixelPercentageDistinctCount != normalizedPixelPercentageCollection.Length) check = true; + fileInfoCollection = directoryInfo.GetFiles($"{item.Property.Id.Value}*.json", SearchOption.TopDirectoryOnly); + if (fileInfoCollection.Length < normalizedPixelPercentageDistinctCount) + check = true; + if (!check && _Configuration.CheckJsonForDistanceResults) + { + for (int j = 0; j < fileInfoCollection.Length; j++) + { + json = Shared.Models.Stateless.Methods.IIndex.GetJson(fileInfoCollection[j].FullName, fileInfoCollection[j]); + if (!_Configuration.PropertiesChangedForDistance && Shared.Models.Stateless.Methods.IFace.GetFace(fileInfoCollection[j].FullName) is null) + { + check = true; + break; + } + } + if (!check && string.IsNullOrEmpty(json)) + check = true; + } } if (check) continue; @@ -278,23 +277,23 @@ internal class E_Distance { DateTime? updateToWhenMatches = dateTime; List> subFileTuples = new(); - List distanceHolders = GetDistanceHolder(filteredItems, directories); + List<(DistanceHolder, FaceRecognitionDotNet.FaceEncoding?)> distanceHolders = GetDistanceHolder(filteredItems, directories); SaveDistanceResults(updateDateWhenMatches, updateToWhenMatches, subFileTuples, distanceHolders); } - _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(directoryInfoCollection[0].Replace("<>", "()")); + _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(directoryInfoCollection[0].Replace("<>", "()")); } - private List<(string, List>)> GetFiles(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string outputResolution) + private List<(string, List>)> GetFiles(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string outputResolution) { string json; - List>? facesKeyValuePairCollection; - List<(string, List>)> results = new(); + List>? facesKeyValuePairCollection; + List<(string, List>)> results = new(); string dFacesCollectionDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(D_Face), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "[[]]"); string[] dFacesCollectionFiles = Directory.GetFiles(dFacesCollectionDirectory, "*.json", SearchOption.TopDirectoryOnly); foreach (string dFacesCollectionFile in dFacesCollectionFiles) { json = File.ReadAllText(dFacesCollectionFile); - facesKeyValuePairCollection = JsonSerializer.Deserialize>>(json); + facesKeyValuePairCollection = JsonSerializer.Deserialize>>(json); if (facesKeyValuePairCollection is null) continue; results.Add(new(dFacesCollectionFile, facesKeyValuePairCollection)); @@ -302,21 +301,21 @@ internal class E_Distance return results; } - private static List<(string, List, List)> GetMatches(List<(string, List>)> files) + private static List<(string, List, List)> GetMatches(List<(string, List>)> files) { - List<(string, List, List)> results = new(); - FaceEncoding faceEncoding; - List faces; - List faceEncodings; - foreach ((string, List>) file in files) + List<(string, List, List)> results = new(); + FaceRecognitionDotNet.FaceEncoding faceEncoding; + List faces; + List faceEncodings; + foreach ((string, List>) file in files) { faces = new(); faceEncodings = new(); - foreach (KeyValuePair keyValuePair in file.Item2) + foreach (KeyValuePair keyValuePair in file.Item2) { - foreach (Shared.Models.Face face in keyValuePair.Value) + foreach (Face face in keyValuePair.Value) { - if (!face.Populated) + if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) continue; faces.Add(face); faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding); @@ -339,7 +338,7 @@ internal class E_Distance return result; } - private void Save(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string outputResolution, string eDistanceCollectionDirectory, int k, string relativePath, Shared.Models.Face face, List> faceAndFaceDistanceCollection) + private void Save(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string outputResolution, string eDistanceCollectionDirectory, int k, string relativePath, Face face, List> faceAndFaceDistanceCollection) { if (string.IsNullOrEmpty(eDistanceCollectionDirectory)) eDistanceCollectionDirectory = Path.Combine(Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(configuration, model, predictorModel, nameof(E_Distance), outputResolution, includeResizeGroup: true, includeModel: true, includePredictorModel: true), "[]"); @@ -349,12 +348,12 @@ internal class E_Distance _ = Directory.CreateDirectory(jsonDirectory); string json = JsonSerializer.Serialize(faceAndFaceDistanceCollection, _WriteIndentedJsonSerializerOptions); string jsonFile = Path.Combine(jsonDirectory, $"{k} - {fileNameWithoutExtension}.nosj"); - _ = Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches: true, compareBeforeWrite: true); + _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches: true, compareBeforeWrite: true); } - private static Tuple Get(FaceEncoding faceEncoding, (string, List, List) match) + private static Tuple Get(FaceRecognitionDotNet.FaceEncoding faceEncoding, (string, List, List) match) { - Tuple result; + Tuple result; double[] faceDistances = FaceRecognition.FaceDistances(match.Item3, faceEncoding).ToArray(); int index = GetIndex(faceDistances); result = new(match.Item2[index], faceDistances[index]); @@ -366,14 +365,14 @@ internal class E_Distance if (_Log is null) throw new NullReferenceException(nameof(_Log)); string? relativePath; - Shared.Models.Face face; + Face face; ParallelOptions parallelOptions = new(); - FaceEncoding faceEncoding; + FaceRecognitionDotNet.FaceEncoding faceEncoding; string eDistanceCollectionDirectory = string.Empty; - Tuple faceAndFaceDistance; - List> faceAndFaceDistanceCollection; - List<(string, List>)> files = GetFiles(configuration, model, predictorModel, outputResolution); - List<(string, List, List)> matches = GetMatches(files); + Tuple faceAndFaceDistance; + List> faceAndFaceDistanceCollection; + List<(string, List>)> files = GetFiles(configuration, model, predictorModel, outputResolution); + List<(string, List, List)> matches = GetMatches(files); if (files.Count != matches.Count) throw new Exception(); int filesCount = files.Count; @@ -386,13 +385,15 @@ internal class E_Distance continue; for (int k = 0; k < files[i].Item2[j].Value.Length; k++) { - if (!files[i].Item2[j].Value[k].Populated) - continue; face = files[i].Item2[j].Value[k]; + if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) + continue; faceAndFaceDistanceCollection = new(matches.Count); relativePath = Path.GetDirectoryName(face.RelativePath); if (string.IsNullOrEmpty(relativePath)) continue; + if (face.FaceEncoding is null) + continue; faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding); _ = Parallel.For(0, matches.Count, parallelOptions, z => { @@ -423,32 +424,32 @@ internal class E_Distance return result; } - private static FaceEncoding? GetFaceEncoding(IFace face) + private static FaceRecognitionDotNet.FaceEncoding? GetFaceEncoding(Face face) { - FaceEncoding? result; - if (!face.Populated) + FaceRecognitionDotNet.FaceEncoding? result; + if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) result = null; else result = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding); return result; } - private static (int index, double sum) GetIndexAndSum(int i, List results) + private static (int index, double sum) GetIndexAndSum(int i, List results) { List faceDistances = FaceRecognition.FaceDistances(results, results[i]); return new(i, faceDistances.Sum()); } - private static List GetFaceEncodings(int maxDegreeOfParallelism, List<(DateTime MinimumDateTime, bool? IsWrongYear, Shared.Models.PersonBirthday PersonBirthday, IFace Face)> collection) + private static List GetFaceEncodings(int maxDegreeOfParallelism, List<(DateTime MinimumDateTime, bool? IsWrongYear, PersonBirthday PersonBirthday, Face Face)> collection) { - List results; + List results; if (maxDegreeOfParallelism == 1) { results = new(); - FaceEncoding faceEncoding; - foreach ((DateTime _, bool? _, Shared.Models.PersonBirthday _, IFace face) in collection) + FaceRecognitionDotNet.FaceEncoding faceEncoding; + foreach ((DateTime _, bool? _, PersonBirthday _, Face face) in collection) { - if (!face.Populated) + if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) continue; faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding); results.Add(faceEncoding); @@ -460,7 +461,7 @@ internal class E_Distance ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism }; _ = Parallel.For(0, collection.Count, parallelOptions, i => { - FaceEncoding? faceEncoding = GetFaceEncoding(collection[i].Face); + FaceRecognitionDotNet.FaceEncoding? faceEncoding = GetFaceEncoding(collection[i].Face); if (faceEncoding is not null) { lock (results) @@ -518,12 +519,12 @@ internal class E_Distance return results; } - private static List<(DateTime, bool?, Shared.Models.PersonBirthday, FaceEncoding[])> GetThreeSigmaFaceEncodings(int maxDegreeOfParallelism, Dictionary> keyValuePairs) + private static List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> GetThreeSigmaFaceEncodings(int maxDegreeOfParallelism, Dictionary> keyValuePairs) { - List<(DateTime, bool?, Shared.Models.PersonBirthday, FaceEncoding[])> results = new(); + List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> results = new(); const int zero = 0; - List faceEncodings; - foreach (KeyValuePair> keyValuePair in keyValuePairs) + List faceEncodings; + foreach (KeyValuePair> keyValuePair in keyValuePairs) { faceEncodings = GetFaceEncodings(maxDegreeOfParallelism, keyValuePair.Value); results.Add(new(keyValuePair.Value[zero].MinimumDateTime, keyValuePair.Value[zero].IsWrongYear, keyValuePair.Value[zero].PersonBirthday, faceEncodings.ToArray())); @@ -531,7 +532,7 @@ internal class E_Distance return results; } - private static Closest? GetClosestParallelFor(DateTime minimumDateTime, bool? isWrongYear, IFace face, FaceEncoding faceEncoding, (DateTime MinimumDateTime, bool? IsWrongYear, Shared.Models.PersonBirthday PersonBirthday, FaceEncoding[] FaceEncodings) tuple) + private static Closest? GetClosestParallelFor(DateTime minimumDateTime, bool? isWrongYear, Face face, FaceRecognitionDotNet.FaceEncoding faceEncoding, (DateTime MinimumDateTime, bool? IsWrongYear, PersonBirthday PersonBirthday, FaceRecognitionDotNet.FaceEncoding[] FaceEncodings) tuple) { Closest? result; if (isWrongYear.HasValue && !isWrongYear.Value && minimumDateTime < tuple.PersonBirthday.Value) @@ -540,29 +541,31 @@ internal class E_Distance { List faceDistances = FaceRecognition.FaceDistances(tuple.FaceEncodings, faceEncoding); result = new(face.Location?.NormalizedPixelPercentage, tuple.MinimumDateTime, tuple.IsWrongYear, tuple.PersonBirthday, faceDistances); - if (result.Minimum > Closest.MaximumMinimum) + if (result.Minimum > Shared.Models.Stateless.Methods.IClosest.MaximumMinimum) result = null; } return result; } - private static Closest[] GetClosestCollection(int maxDegreeOfParallelism, List<(DateTime, bool?, Shared.Models.PersonBirthday, FaceEncoding[])> collection, DateTime itemMinimumDateTime, bool? itemIsWrongYear, IFace face) + private static Closest[] GetClosestCollection(int maxDegreeOfParallelism, List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> collection, DateTime itemMinimumDateTime, bool? itemIsWrongYear, Face face) { Closest[] results; List closestCollection; - FaceEncoding faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding); + if (face.FaceEncoding is null) + throw new NullReferenceException(nameof(face.FaceEncoding)); + FaceRecognitionDotNet.FaceEncoding faceEncoding = FaceRecognition.LoadFaceEncoding(face.FaceEncoding.RawEncoding); if (maxDegreeOfParallelism == 1) { closestCollection = new(); Closest closest; List faceDistances; - foreach ((DateTime minimumDateTime, bool? isWrongYear, Shared.Models.PersonBirthday personBirthday, FaceEncoding[] faceEncodings) in collection) + foreach ((DateTime minimumDateTime, bool? isWrongYear, PersonBirthday personBirthday, FaceRecognitionDotNet.FaceEncoding[] faceEncodings) in collection) { if (itemIsWrongYear.HasValue && !itemIsWrongYear.Value && itemMinimumDateTime < personBirthday.Value) continue; faceDistances = FaceRecognition.FaceDistances(faceEncodings, faceEncoding); closest = new(face.Location?.NormalizedPixelPercentage, minimumDateTime, isWrongYear, personBirthday, faceDistances); - if (closest.Minimum > Closest.MaximumMinimum) + if (closest.Minimum > Shared.Models.Stateless.Methods.IClosest.MaximumMinimum) continue; closestCollection.Add(closest); } @@ -581,14 +584,14 @@ internal class E_Distance } }); } - results = Closest.Get(closestCollection); + results = Shared.Models.Stateless.Methods.IClosest.Get(closestCollection); return results; } - private static void AddClosest(int maxDegreeOfParallelism, string argZero, PropertyLogic propertyLogic, List containers, List<(DateTime, bool?, Shared.Models.PersonBirthday, FaceEncoding[])> collection) + private static void AddClosest(int maxDegreeOfParallelism, string argZero, Map.Models.MapLogic mapLogic, List containers, List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> collection) { string key; - IFace face; + Face face; Closest closest; string personKey; bool? itemIsWrongYear; @@ -606,11 +609,11 @@ internal class E_Distance { if (item.ImageFileHolder is null || item.Property is null || item.Named.Any()) continue; - itemMinimumDateTime = Property.Models.Stateless.A_Property.GetMinimumDateTime(item.Property); + itemMinimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property); if (itemMinimumDateTime is null) continue; - (itemIsWrongYear, _) = item.IsWrongYear(); - if (Closest.SkipIsWrongYear && itemIsWrongYear.HasValue && itemIsWrongYear.Value) + (itemIsWrongYear, _) = Map.Models.MapLogic.IsWrongYear(item); + if (Shared.Models.Stateless.Methods.IClosest.SkipIsWrongYear && itemIsWrongYear.HasValue && itemIsWrongYear.Value) continue; item.Closest.Clear(); for (int i = 0; i < item.Faces.Count; i++) @@ -618,9 +621,9 @@ internal class E_Distance face = item.Faces[i]; closest = new(face.Location?.NormalizedPixelPercentage, itemMinimumDateTime.Value, itemIsWrongYear); item.Closest.Add(closest); - if (!face.Populated) + if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) continue; - deterministicHashCodeKey = Named.GetDeterministicHashCodeKey(item, face); + deterministicHashCodeKey = Shared.Models.Stateless.Methods.INamed.GetDeterministicHashCodeKey(item, face); closestCollection = GetClosestCollection(maxDegreeOfParallelism, collection, itemMinimumDateTime.Value, itemIsWrongYear, face); for (int j = 0; j < closestCollection.Length; j++) { @@ -628,12 +631,12 @@ internal class E_Distance if (closest.PersonBirthday is null) continue; personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(closest.PersonBirthday); - if (propertyLogic.IncorrectDeterministicHashCodeKeyValuePairs.ContainsKey(deterministicHashCodeKey) && propertyLogic.IncorrectDeterministicHashCodeKeyValuePairs[deterministicHashCodeKey].Contains(personKey)) + if (mapLogic.IncorrectDeterministicHashCodeKeyValuePairs.ContainsKey(deterministicHashCodeKey) && mapLogic.IncorrectDeterministicHashCodeKeyValuePairs[deterministicHashCodeKey].Contains(personKey)) continue; - key = Item.GetKey(closest.MinimumDateTime, closest.IsWrongYear, closest.PersonBirthday); + key = Map.Models.MapLogic.GetKey(closest.MinimumDateTime, closest.IsWrongYear, closest.PersonBirthday); if (!results.ContainsKey(key)) results.Add(key, 0); - else if (results[key] > Closest.MaximumPer) + else if (results[key] > Shared.Models.Stateless.Methods.IClosest.MaximumPer) continue; results[key] += 1; item.Closest[0] = closest; @@ -644,12 +647,12 @@ internal class E_Distance } } - internal static List<(DateTime, bool?, Shared.Models.PersonBirthday, FaceEncoding[])> ParallelWork(int maxDegreeOfParallelism, string argZero, PropertyLogic propertyLogic, List containers) + internal static List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> ParallelWork(int maxDegreeOfParallelism, string argZero, Map.Models.MapLogic mapLogic, List containers) { - List<(DateTime, bool?, Shared.Models.PersonBirthday, FaceEncoding[])> results; - Dictionary> keyValuePairs = Item.GetKeyValuePairs(argZero, containers); + List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> results; + Dictionary> keyValuePairs = Map.Models.MapLogic.GetKeyValuePairs(argZero, containers); results = GetThreeSigmaFaceEncodings(maxDegreeOfParallelism, keyValuePairs); - AddClosest(maxDegreeOfParallelism, argZero, propertyLogic, containers, results); + AddClosest(maxDegreeOfParallelism, argZero, mapLogic, containers, results); return results; } @@ -677,27 +680,27 @@ internal class E_Distance continue; if (!fileInfo.Directory.Exists) fileInfo.Directory.Create(); - _ = Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true); + _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true); } } } - internal static void SaveThreeSigmaFaceEncodings(List<(DateTime, bool?, Shared.Models.PersonBirthday, FaceEncoding[])> collection, Dictionary> peopleCollection, string eDistanceCollectionDirectory) + internal static void SaveThreeSigmaFaceEncodings(List<(DateTime, bool?, PersonBirthday, FaceRecognitionDotNet.FaceEncoding[])> collection, Dictionary> peopleCollection, string eDistanceCollectionDirectory) { string json; string checkFile; string personKey; string directory; List rawEncodings; - Shared.Models.Person person; + Person person; const string facePopulatedKey = "ThreeSigma"; const string pattern = @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]"; - foreach ((DateTime minimumDateTime, bool? isWrongYear, Shared.Models.PersonBirthday personBirthday, FaceEncoding[] faceEncodings) in collection) + foreach ((DateTime minimumDateTime, bool? isWrongYear, PersonBirthday personBirthday, FaceRecognitionDotNet.FaceEncoding[] faceEncodings) in collection) { rawEncodings = new(); checkFile = string.Empty; personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthday); - directory = Item.GetDirectory(eDistanceCollectionDirectory, facePopulatedKey, minimumDateTime, isWrongYear, personBirthday, personKey); + directory = Map.Models.MapLogic.GetDirectory(eDistanceCollectionDirectory, facePopulatedKey, minimumDateTime, isWrongYear, personBirthday, personKey); if (!peopleCollection.ContainsKey(personKey)) continue; person = peopleCollection[personKey][0]; @@ -709,13 +712,14 @@ internal class E_Distance for (int i = 0; i < faceEncodings.Length; i++) rawEncodings.Add(faceEncodings[i].GetRawEncoding()); json = JsonSerializer.Serialize(rawEncodings, new JsonSerializerOptions { WriteIndented = true }); - _ = Property.Models.Stateless.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: true, compareBeforeWrite: true); + _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: true, compareBeforeWrite: true); } } - internal static List<(FileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile)> GetClosest(string argZero, List containers, Dictionary> peopleCollection, string eDistanceContentDirectory, string dFacesContentDirectory) + internal static List<(IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile)> GetClosest(string argZero, List containers, Dictionary> peopleCollection, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, string eDistanceContentDirectory) { - List<(FileHolder?, string, FileInfo?, string, string)> results = new(); + List<(IFileHolder?, string, FileInfo?, string, string)> results = new(); + Person person; string checkFile; string directory; string personKey; @@ -725,7 +729,8 @@ internal class E_Distance string? directoryName; string facesDirectory; string personDirectory; - Shared.Models.Person person; + FileInfo landmarkFileInfo; + string landmarksDirectory; double deterministicHashCodeKey; const string facePopulatedKey = "Closest"; const string pattern = @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]"; @@ -749,7 +754,7 @@ internal class E_Distance if (closest.Average is null || closest.NormalizedPixelPercentage is null || closest.PersonBirthday is null) continue; personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(closest.PersonBirthday); - directory = Item.GetDirectory(eDistanceContentDirectory, facePopulatedKey, closest.MinimumDateTime, closest.IsWrongYear, closest.PersonBirthday, personKey); + directory = Map.Models.MapLogic.GetDirectory(eDistanceContentDirectory, facePopulatedKey, closest.MinimumDateTime, closest.IsWrongYear, closest.PersonBirthday, personKey); if (!peopleCollection.ContainsKey(personKey)) personDirectory = string.Empty; else @@ -760,9 +765,11 @@ internal class E_Distance results.Add(new(null, personDirectory, null, string.Empty, string.Empty)); } facesDirectory = string.Concat(dFacesContentDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension)); - deterministicHashCodeKey = Named.GetDeterministicHashCodeKey(item, closest); + landmarksDirectory = string.Concat(d2ResultsFullGroupDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension)); + deterministicHashCodeKey = Shared.Models.Stateless.Methods.INamed.GetDeterministicHashCodeKey(item, closest); checkFile = Path.Combine(directory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}"); faceFileInfo = new(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.png")); + landmarkFileInfo = new(Path.Combine(landmarksDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.gif")); if (string.IsNullOrEmpty(personDirectory)) shortcutFile = string.Empty; else @@ -774,10 +781,10 @@ internal class E_Distance return results; } - internal static void SaveClosest(string argZero, List containers, Dictionary> peopleCollection, string eDistanceContentDirectory, string dFacesContentDirectory) + internal static void SaveClosest(string argZero, List containers, Dictionary> peopleCollection, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, string eDistanceContentDirectory) { WindowsShortcut windowsShortcut; - List<(FileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile)> collection = GetClosest(argZero, containers, peopleCollection, eDistanceContentDirectory, dFacesContentDirectory); + List<(IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile)> collection = GetClosest(argZero, containers, peopleCollection, dFacesContentDirectory, d2ResultsFullGroupDirectory, eDistanceContentDirectory); string[] directories = (from l in collection select l.directory).Distinct().ToArray(); foreach (string directory in directories) { @@ -786,7 +793,7 @@ internal class E_Distance if (!Directory.Exists(directory)) _ = Directory.CreateDirectory(directory); } - foreach ((FileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile) in collection) + foreach ((IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile) in collection) { if (string.IsNullOrEmpty(directory) || string.IsNullOrEmpty(checkFile) || resizedFileHolder is null || faceFileInfo is null) continue; @@ -797,7 +804,7 @@ internal class E_Distance else File.Copy(resizedFileHolder.FullName, checkFile); } - foreach ((FileHolder? resizedFileHolder, string directory, FileInfo? _, string checkFile, string shortcutFile) in collection) + foreach ((IFileHolder? resizedFileHolder, string directory, FileInfo? _, string checkFile, string shortcutFile) in collection) { if (string.IsNullOrEmpty(directory) || string.IsNullOrEmpty(checkFile) || resizedFileHolder is null) continue; diff --git a/Instance/Models/_F_Random.cs b/Instance/Models/_F_Random.cs index 852bcd5..d72ad9d 100644 --- a/Instance/Models/_F_Random.cs +++ b/Instance/Models/_F_Random.cs @@ -28,8 +28,6 @@ internal class F_Random private bool IsIgnoreRelativePath(string directory) { bool result = false; - if (_Configuration?.PropertyConfiguration is null) - throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration)); string? checkDirectory = Path.GetFullPath(directory); for (int i = 0; i < int.MaxValue; i++) { @@ -71,7 +69,7 @@ internal class F_Random relativePaths = (from l in relativePaths orderby random.NextDouble() select l).ToList(); jsonFile = Path.Combine(fRandomCollectionDirectory, $"{dateTime.AddDays(i):MM-dd}.json"); json = JsonSerializer.Serialize(relativePaths, _WriteIndentedJsonSerializerOptions); - _ = Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches: false, compareBeforeWrite: false); + _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches: false, compareBeforeWrite: false); if (!_Configuration.SaveFullYearOfRandomFiles) break; } @@ -81,7 +79,7 @@ internal class F_Random ignoreRelativePaths = (from l in ignoreRelativePaths orderby random.NextDouble() select l).ToList(); jsonFile = Path.Combine(fRandomCollectionDirectory, "01-01.txt"); json = JsonSerializer.Serialize(ignoreRelativePaths, _WriteIndentedJsonSerializerOptions); - _ = Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches: false, compareBeforeWrite: false); + _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches: false, compareBeforeWrite: false); } } diff --git a/Instance/Models/_G2_Identify.cs b/Instance/Models/_G2_Identify.cs index d0b0bec..97f5e68 100644 --- a/Instance/Models/_G2_Identify.cs +++ b/Instance/Models/_G2_Identify.cs @@ -1,7 +1,6 @@ using Phares.Shared; using System.Text.Json; using System.Text.Json.Serialization; -using View_by_Distance.Property.Models; using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Methods; @@ -103,7 +102,7 @@ public class G2_Identify : Shared.Models.Properties.IIdentify, IIdentify json = JsonSerializer.Serialize(resultKeyValuePairs, _WriteIndentedJsonSerializerOptions); if (!isEnvironment.DebuggerWasAttachedDuringConstructor) throw new Exception("Only allowed when debugger is attached during constructor!"); - _ = Property.Models.Stateless.IPath.WriteAllText(named.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true); + _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(named.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true); } } @@ -189,7 +188,7 @@ public class G2_Identify : Shared.Models.Properties.IIdentify, IIdentify string jsonFile; string directoryFullName; string fileNameWithoutExtension; - string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}"); + string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(Property.Models.A_Property), "{}"); string g2IdentifyCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(G2_Identify), "[]"); Dictionary>> keyValuePairs = new(); foreach (G2_Identify identified in identifiedCollection) @@ -221,7 +220,7 @@ public class G2_Identify : Shared.Models.Properties.IIdentify, IIdentify _ = Directory.CreateDirectory(directoryFullName); jsonFile = string.Concat(g2IdentifyCollectionDirectory, keyValuePair.Key, ".json"); json = JsonSerializer.Serialize(keyValuePair.Value, _WriteIndentedJsonSerializerOptions); - if (!Property.Models.Stateless.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches: true, compareBeforeWrite: true)) + if (!Shared.Models.Stateless.Methods.IPath.WriteAllText(jsonFile, json, updateDateWhenMatches: true, compareBeforeWrite: true)) continue; } } diff --git a/Instance/Models/_G_Index.cs b/Instance/Models/_G_Index.cs index 147afad..4d21b9c 100644 --- a/Instance/Models/_G_Index.cs +++ b/Instance/Models/_G_Index.cs @@ -1,6 +1,5 @@ using System.Text.Json; using System.Text.Json.Serialization; -using View_by_Distance.Property.Models; using View_by_Distance.Shared.Models.Methods; using View_by_Distance.Shared.Models.Stateless; @@ -76,11 +75,11 @@ public class G_Index : Shared.Models.Properties.IIndex, IIndex return result; } - private void WriteNeeded(List indices, List, string, A_Property>> neededTuples) + private void WriteNeeded(List indices, List, string, Shared.Models.Property>> neededTuples) { string json; DateTime dateTime; - A_Property property; + Shared.Models.Property property; G_Index indexInfo; int maxIndexPlusOne; DateTime?[] dateTimes; @@ -91,7 +90,7 @@ public class G_Index : Shared.Models.Properties.IIndex, IIndex maxIndexPlusOne = 1000000; throw new Exception("Are you sure exception. Use debugger to step over."); } - foreach (Tuple, string, A_Property> tuple in neededTuples) + foreach (Tuple, string, Shared.Models.Property> tuple in neededTuples) { maxIndexPlusOne += 1; property = tuple.Item3; @@ -99,7 +98,7 @@ public class G_Index : Shared.Models.Properties.IIndex, IIndex dateTime = (from l in dateTimes where l.HasValue select l.Value).Min(); indexInfo = new(dateTime, maxIndexPlusOne, tuple.Item1); json = JsonSerializer.Serialize(indexInfo, _WriteIndentedJsonSerializerOptions); - if (!Property.Models.Stateless.IPath.WriteAllText(tuple.Item2, json, updateDateWhenMatches: true, compareBeforeWrite: true)) + if (!Shared.Models.Stateless.Methods.IPath.WriteAllText(tuple.Item2, json, updateDateWhenMatches: true, compareBeforeWrite: true)) continue; } } @@ -114,24 +113,24 @@ public class G_Index : Shared.Models.Properties.IIndex, IIndex indices = (from l in tuple.Item2 select l.Value).ToArray(); directoryInfoCollection = Property.Models.Stateless.IResult.GetDirectoryInfoCollection(configuration, model, predictorModel, tuple.Item1, nameof(G_Index), outputResolution, includeResizeGroup: false, includeModel: false, includePredictorModel: false, contentDescription: string.Empty, singletonDescription: string.Empty, collectionDescription: "Unknown A"); json = JsonSerializer.Serialize(indices, _WriteIndentedJsonSerializerOptions); - if (!Property.Models.Stateless.IPath.WriteAllText(string.Concat(directoryInfoCollection[0].Replace("<>", "[]"), ".json"), json, updateDateWhenMatches: true, compareBeforeWrite: true)) + if (!Shared.Models.Stateless.Methods.IPath.WriteAllText(string.Concat(directoryInfoCollection[0].Replace("<>", "[]"), ".json"), json, updateDateWhenMatches: true, compareBeforeWrite: true)) continue; } } - private void AppendTSV(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string outputResolution, Dictionary>> filePropertiesKeyValuePairs) + private void AppendTSV(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string outputResolution, Dictionary>> filePropertiesKeyValuePairs) { - A_Property property; + Shared.Models.Property property; DateTime?[] dateTimes; DateTime? maximumDateTime; DateTime? minimumDateTime; List directoryInfoCollection; long ticks = System.DateTime.Now.Ticks; - foreach (KeyValuePair>> tuples in filePropertiesKeyValuePairs) + foreach (KeyValuePair>> tuples in filePropertiesKeyValuePairs) { maximumDateTime = null; minimumDateTime = null; - foreach (Tuple tuple in tuples.Value) + foreach (Tuple tuple in tuples.Value) { property = tuple.Item2; dateTimes = new DateTime?[] { maximumDateTime, minimumDateTime, property.CreationTime, property.LastWriteTime, property.DateTime, property.DateTimeDigitized, property.DateTimeOriginal, property.GPSDateStamp }; @@ -142,7 +141,7 @@ public class G_Index : Shared.Models.Properties.IIndex, IIndex } } - internal void SetIndex(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string outputResolution, Dictionary>> filePropertiesKeyValuePairs) + internal void SetIndex(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string outputResolution, Dictionary>> filePropertiesKeyValuePairs) { FileInfo fileInfo; G_Index indexInfo; @@ -151,7 +150,7 @@ public class G_Index : Shared.Models.Properties.IIndex, IIndex Dictionary valuePairs; List directoryInfoCollection; List parseExceptions = new(); - List, string, A_Property>> neededTuples = new(); + List, string, Shared.Models.Property>> neededTuples = new(); List>> indexInfoTuples = new(); for (short i = 0; i < short.MaxValue; i++) { @@ -164,11 +163,11 @@ public class G_Index : Shared.Models.Properties.IIndex, IIndex parseExceptions.Clear(); } neededTuples.Clear(); - foreach (KeyValuePair>> tuples in filePropertiesKeyValuePairs) + foreach (KeyValuePair>> tuples in filePropertiesKeyValuePairs) { valuePairs = new Dictionary(); directoryInfoCollection = Property.Models.Stateless.IResult.GetDirectoryInfoCollection(configuration, model, predictorModel, tuples.Key, nameof(G_Index), outputResolution, includeResizeGroup: false, includeModel: false, includePredictorModel: false, contentDescription: string.Empty, singletonDescription: "Unknown C", collectionDescription: string.Empty); - foreach (Tuple tuple in tuples.Value) + foreach (Tuple tuple in tuples.Value) { fileInfo = new FileInfo(Path.Combine(directoryInfoCollection[0].Replace("<>", "{}"), string.Concat(Path.GetFileNameWithoutExtension(tuple.Item1), ".json"))); if (!fileInfo.Exists) @@ -191,7 +190,7 @@ public class G_Index : Shared.Models.Properties.IIndex, IIndex valuePairs.Add(indexInfo.Index.Value, indexInfo); } else - neededTuples.Add(new Tuple, string, A_Property>(new List { tuple.Item1 }, fileInfo.FullName, tuple.Item2)); + neededTuples.Add(new Tuple, string, Shared.Models.Property>(new List { tuple.Item1 }, fileInfo.FullName, tuple.Item2)); } indexInfoTuples.Add(new Tuple>(tuples.Key, valuePairs)); } diff --git a/Instance/appsettings.Development.json b/Instance/appsettings.Development.json index 5bd1fe0..63696c0 100644 --- a/Instance/appsettings.Development.json +++ b/Instance/appsettings.Development.json @@ -52,7 +52,7 @@ "Configuration": { "CheckJsonForDistanceResults": false, "CrossDirectoryMaxItemsInDistanceCollection": 7, - "DateGroup": "2022-08-14", + "DateGroup": "2022-08-22", "DistanceFactor": 8, "FileNameDirectorySeparator": ".Z.", "ForceFaceLastWriteTimeToCreationTime": false, @@ -62,7 +62,7 @@ "LoadOrCreateThenSaveIndex": false, "LocationConfidenceFactor": 2, "MappedMaxIndex": 1034720, - "MaxImagesInDirectoryForTopLevelFirstPass": 50, + "MaxImagesInDirectoryForTopLevelFirstPass": 10, "MaxItemsInDistanceCollection": 50, "ModelDirectory": "C:/GitHub/dlib-models", "ModelName": "Hog", @@ -85,7 +85,7 @@ "PropertiesChangedForResize": false, "Reverse": false, "xRootDirectory": "C:/Tmp/phares/Pictures", - "RootDirectory": "C:/Tmp/Phares/Compare/Images 2022-08-14 - b756859b616424dc98b7742a64c15a8951632473 - III", + "RootDirectory": "C:/Tmp/Phares/Compare/Images 2022-08-22 - b756859b616424dc98b7742a64c15a8951632473 - III", "SaveFullYearOfRandomFiles": true, "SaveResizedSubFiles": true, "SkipSearch": false, diff --git a/Instance/appsettings.Staging.json b/Instance/appsettings.Staging.json index 4e85c23..c620372 100644 --- a/Instance/appsettings.Staging.json +++ b/Instance/appsettings.Staging.json @@ -52,7 +52,7 @@ "Configuration": { "CheckJsonForDistanceResults": false, "CrossDirectoryMaxItemsInDistanceCollection": 7, - "DateGroup": "2022-08-14", + "DateGroup": "2022-08-22", "DistanceFactor": 8, "FileNameDirectorySeparator": ".Z.", "ForceFaceLastWriteTimeToCreationTime": false, @@ -62,7 +62,7 @@ "LoadOrCreateThenSaveIndex": false, "LocationConfidenceFactor": 2, "MappedMaxIndex": 1034720, - "MaxImagesInDirectoryForTopLevelFirstPass": 50, + "MaxImagesInDirectoryForTopLevelFirstPass": 10, "MaxItemsInDistanceCollection": 50, "ModelDirectory": "L:/GitHub/dlib-models", "ModelName": "Hog", diff --git a/Instance/appsettings.json b/Instance/appsettings.json index 9f27b74..41d5f9b 100644 --- a/Instance/appsettings.json +++ b/Instance/appsettings.json @@ -52,7 +52,7 @@ "Configuration": { "CheckJsonForDistanceResults": false, "CrossDirectoryMaxItemsInDistanceCollection": 7, - "DateGroup": "2022-08-14", + "DateGroup": "2022-08-22", "DistanceFactor": 8, "FileNameDirectorySeparator": ".Z.", "ForceFaceLastWriteTimeToCreationTime": false, @@ -62,7 +62,7 @@ "LoadOrCreateThenSaveIndex": false, "LocationConfidenceFactor": 2, "MappedMaxIndex": 1034720, - "MaxImagesInDirectoryForTopLevelFirstPass": 50, + "MaxImagesInDirectoryForTopLevelFirstPass": 10, "MaxItemsInDistanceCollection": 50, "ModelDirectory": "C:/GitHub/dlib-models", "ModelName": "Hog", diff --git a/Map/.vscode/settings.json b/Map/.vscode/settings.json new file mode 100644 index 0000000..8c8a882 --- /dev/null +++ b/Map/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "cSpell.words": [ + "dlib", + "Exif", + "Serilog" + ] +} \ No newline at end of file diff --git a/Map/Map.csproj b/Map/Map.csproj new file mode 100644 index 0000000..080a285 --- /dev/null +++ b/Map/Map.csproj @@ -0,0 +1,46 @@ + + + enable + 10.0 + enable + library + win-x64 + net6.0 + + + Phares.View.by.Distance.Map + false + 6.0.100.1 + Mike Phares + Phares + true + snupkg + + + true + true + true + + + Windows + + + OSX + + + Linux + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Map/Models/MapLogic.cs b/Map/Models/MapLogic.cs new file mode 100644 index 0000000..b389d25 --- /dev/null +++ b/Map/Models/MapLogic.cs @@ -0,0 +1,546 @@ +using System.Diagnostics; +using System.Text.Json; +using View_by_Distance.Property.Models; + +namespace View_by_Distance.Map.Models; + +public class MapLogic +{ + + protected readonly List<(int, string[])> _AllCollection; + protected readonly Dictionary _KeyValuePairs; + protected readonly Dictionary _IndicesFromNew; + protected readonly string _DeterministicHashCodeRootDirectory; + protected readonly Dictionary _SixCharacterNamedFaceInfo; + protected readonly Dictionary _NamedFaceInfoDeterministicHashCodeKeyValuePairs; + protected readonly Dictionary _NamedDeterministicHashCodeKeyValuePairs; + protected readonly Dictionary _IncorrectDeterministicHashCodeKeyValuePairs; + + public Dictionary KeyValuePairs => _KeyValuePairs; + public Dictionary IndicesFromNew => _IndicesFromNew; + public string DeterministicHashCodeRootDirectory => _DeterministicHashCodeRootDirectory; + public Dictionary NamedDeterministicHashCodeKeyValuePairs => _NamedDeterministicHashCodeKeyValuePairs; + public Dictionary IncorrectDeterministicHashCodeKeyValuePairs => _IncorrectDeterministicHashCodeKeyValuePairs; + public Dictionary NamedFaceInfoDeterministicHashCodeKeyValuePairs => _NamedFaceInfoDeterministicHashCodeKeyValuePairs; + + private readonly Serilog.ILogger? _Log; + private readonly Configuration _Configuration; + + public MapLogic(int maxDegreeOfParallelism, Configuration configuration) + { + _AllCollection = new(); + _Configuration = configuration; + _Log = Serilog.Log.ForContext(); + Dictionary? namedFaceInfoDeterministicHashCode; + if (configuration.VerifyToSeason is null || !configuration.VerifyToSeason.Any()) + throw new Exception(); + string json; + string[] files; + string fullPath; + Dictionary? keyValuePairs; + string deterministicHashCodeRootDirectory; + List>? collection; + Dictionary indicesFromNew = new(); + Dictionary? sixCharacterNamedFaceInfo; + Dictionary namedDeterministicHashCode = new(); + Dictionary incorrectDeterministicHashCode = new(); + string? rootDirectoryParent = Path.GetDirectoryName(configuration.RootDirectory); + if (string.IsNullOrEmpty(rootDirectoryParent)) + throw new NullReferenceException(nameof(rootDirectoryParent)); + files = Directory.GetFiles(rootDirectoryParent, "*DeterministicHashCode*.json", SearchOption.TopDirectoryOnly); + if (files.Length != 1) + namedFaceInfoDeterministicHashCode = new(); + else + { + json = File.ReadAllText(files[0]); + namedFaceInfoDeterministicHashCode = JsonSerializer.Deserialize>(json); + if (namedFaceInfoDeterministicHashCode is null) + throw new NullReferenceException(nameof(namedFaceInfoDeterministicHashCode)); + } + string[] directories = Directory.GetDirectories(rootDirectoryParent, "*DeterministicHashCode*", SearchOption.TopDirectoryOnly); + if (!directories.Any()) + deterministicHashCodeRootDirectory = string.Empty; + else + { + Dictionary> faces = new(); + deterministicHashCodeRootDirectory = directories[0]; + SetKeyValuePairs(deterministicHashCodeRootDirectory, namedDeterministicHashCode, incorrectDeterministicHashCode, faces); + } + if (!namedFaceInfoDeterministicHashCode.Any()) + sixCharacterNamedFaceInfo = new(); + else + { + files = Directory.GetFiles(rootDirectoryParent, "*SixCharacter*.json", SearchOption.TopDirectoryOnly); + if (files.Length != 1) + sixCharacterNamedFaceInfo = new(); + else + { + json = File.ReadAllText(files[0]); + sixCharacterNamedFaceInfo = JsonSerializer.Deserialize>(json); + if (sixCharacterNamedFaceInfo is null) + throw new NullReferenceException(nameof(sixCharacterNamedFaceInfo)); + } + } + files = Directory.GetFiles(rootDirectoryParent, "*keyValuePairs*.json", SearchOption.TopDirectoryOnly); + if (files.Length != 1) + keyValuePairs = new(); + else + { + json = File.ReadAllText(files[0]); + keyValuePairs = JsonSerializer.Deserialize>(json); + if (keyValuePairs is null) + throw new NullReferenceException(nameof(keyValuePairs)); + } + foreach (string propertyContentCollectionFile in configuration.PropertyContentCollectionFiles) + { + fullPath = Path.GetFullPath(string.Concat(rootDirectoryParent, propertyContentCollectionFile)); + if (fullPath.Contains(configuration.RootDirectory)) + continue; + if (!File.Exists(fullPath)) + continue; + json = File.ReadAllText(fullPath); + collection = JsonSerializer.Deserialize>>(json); + if (collection is null) + throw new NullReferenceException(nameof(collection)); + foreach (KeyValuePair keyValuePair in collection) + { + if (indicesFromNew.ContainsKey(keyValuePair.Key)) + continue; + indicesFromNew.Add(keyValuePair.Key, keyValuePair.Value); + } + } + _KeyValuePairs = keyValuePairs; + _IndicesFromNew = indicesFromNew; + _SixCharacterNamedFaceInfo = sixCharacterNamedFaceInfo; + _NamedDeterministicHashCodeKeyValuePairs = namedDeterministicHashCode; + _DeterministicHashCodeRootDirectory = deterministicHashCodeRootDirectory; + _IncorrectDeterministicHashCodeKeyValuePairs = incorrectDeterministicHashCode; + _NamedFaceInfoDeterministicHashCodeKeyValuePairs = namedFaceInfoDeterministicHashCode; + } + + private static void SetKeyValuePairs(string deterministicHashCodeRootDirectory, List<(string, double)> named, List<(string, double)> incorrect, Dictionary> keyValuePairs) + { + string[] files; + string fileName; + string personKey; + string? checkFile; + string[] yearDirectories; + string[] personKeyDirectories; + string[] personNameDirectories; + double? idAndNormalizedPixelPercentage; + string[] ticksDirectories = Directory.GetDirectories(deterministicHashCodeRootDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string ticksDirectory in ticksDirectories) + { + if (!ticksDirectory.EndsWith(')')) + continue; + personKeyDirectories = Directory.GetDirectories(ticksDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string personKeyDirectory in personKeyDirectories) + { + personKey = Path.GetFileName(personKeyDirectory); + yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string yearDirectory in yearDirectories) + { + files = Directory.GetFiles(yearDirectory, "*", SearchOption.TopDirectoryOnly); + personNameDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string file in files) + { + if (file.EndsWith(".lnk")) + continue; + fileName = Path.GetFileName(file); + idAndNormalizedPixelPercentage = Shared.Models.Stateless.Methods.INamed.GetReversedDeterministicHashCode(fileName); + if (idAndNormalizedPixelPercentage is null) + { + (checkFile, idAndNormalizedPixelPercentage) = Shared.Models.Stateless.Methods.INamed.GetReversedDeterministicHashCode(keyValuePairs, file); + if (idAndNormalizedPixelPercentage is null) + break; + if (!string.IsNullOrEmpty(checkFile)) + File.Move(file, checkFile); + } + incorrect.Add(new(personKey, idAndNormalizedPixelPercentage.Value)); + } + foreach (string personNameDirectory in personNameDirectories) + { + files = Directory.GetFiles(personNameDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string file in files) + { + if (file.EndsWith(".lnk")) + continue; + fileName = Path.GetFileName(file); + idAndNormalizedPixelPercentage = Shared.Models.Stateless.Methods.INamed.GetReversedDeterministicHashCode(fileName); + if (idAndNormalizedPixelPercentage is null) + { + (checkFile, idAndNormalizedPixelPercentage) = Shared.Models.Stateless.Methods.INamed.GetReversedDeterministicHashCode(keyValuePairs, file); + if (idAndNormalizedPixelPercentage is null) + break; + if (!string.IsNullOrEmpty(checkFile)) + File.Move(file, checkFile); + } + named.Add(new(personKey, idAndNormalizedPixelPercentage.Value)); + } + } + } + } + } + } + + private static void SetKeyValuePairs(string deterministicHashCodeRootDirectory, Dictionary namedDeterministicHashCode, Dictionary incorrectDeterministicHashCode, Dictionary> keyValuePairs) + { + Dictionary> namedKeyValuePairs = new(); + Dictionary> incorrectKeyValuePairs = new(); + List<(string PersonKey, double IdAndNormalizedPixelPercentage)> named = new(); + List<(string PersonKey, double IdAndNormalizedPixelPercentage)> incorrect = new(); + SetKeyValuePairs(deterministicHashCodeRootDirectory, named, incorrect, keyValuePairs); + named = (from l in named orderby l.IdAndNormalizedPixelPercentage select l).ToList(); + incorrect = (from l in incorrect orderby l.IdAndNormalizedPixelPercentage select l).ToList(); + foreach ((string personKey, double idAndNormalizedPixelPercentage) in named) + { + if (!namedKeyValuePairs.ContainsKey(idAndNormalizedPixelPercentage)) + namedKeyValuePairs.Add(idAndNormalizedPixelPercentage, new()); + namedKeyValuePairs[idAndNormalizedPixelPercentage].Add(personKey); + } + foreach ((string personKey, double idAndNormalizedPixelPercentage) in incorrect) + { + if (!incorrectKeyValuePairs.ContainsKey(idAndNormalizedPixelPercentage)) + incorrectKeyValuePairs.Add(idAndNormalizedPixelPercentage, new()); + incorrectKeyValuePairs[idAndNormalizedPixelPercentage].Add(personKey); + } + foreach (KeyValuePair> keyValuePair in namedKeyValuePairs) + namedDeterministicHashCode.Add(keyValuePair.Key, keyValuePair.Value.Distinct().ToArray()); + foreach (KeyValuePair> keyValuePair in incorrectKeyValuePairs) + incorrectDeterministicHashCode.Add(keyValuePair.Key, keyValuePair.Value.Distinct().ToArray()); + } + + public void UpdateKeyValuePairs(List containers) + { + Dictionary> keyValuePairs = new(); + Dictionary namedDeterministicHashCode = new(); + Dictionary incorrectDeterministicHashCode = new(); + foreach (Shared.Models.Container container in containers) + { + foreach (Shared.Models.Item item in container.Items) + { + if (item.ImageFileHolder is null || item.Property?.Id is null || !item.Faces.Any()) + continue; + if (keyValuePairs.ContainsKey(item.Property.Id.Value)) + { + if (keyValuePairs[item.Property.Id.Value].Count != item.Faces.Count) + throw new Exception(); + continue; + } + keyValuePairs.Add(item.Property.Id.Value, item.Faces); + } + } + SetKeyValuePairs(_DeterministicHashCodeRootDirectory, namedDeterministicHashCode, incorrectDeterministicHashCode, keyValuePairs); + foreach (KeyValuePair keyValuePair in namedDeterministicHashCode) + _NamedDeterministicHashCodeKeyValuePairs.Add(keyValuePair.Key, keyValuePair.Value); + foreach (KeyValuePair keyValuePair in incorrectDeterministicHashCode) + _IncorrectDeterministicHashCodeKeyValuePairs.Add(keyValuePair.Key, keyValuePair.Value); + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + private long LogDelta(long ticks, string? methodName) + { + long result; + if (_Log is null) + throw new NullReferenceException(nameof(_Log)); + double delta = new TimeSpan(DateTime.Now.Ticks - ticks).TotalMilliseconds; + _Log.Debug($"{methodName} took {Math.Floor(delta)} millisecond(s)"); + result = DateTime.Now.Ticks; + return result; + } + + public void AddToMapLogicAllCollection(Shared.Models.Item[] filteredItems) + { + if (_SixCharacterNamedFaceInfo.Any()) + { + string[] keys; + Shared.Models.Item item; + for (int i = 0; i < filteredItems.Length; i++) + { + item = filteredItems[i]; + if (item.Property?.Id is null) + continue; + foreach (int sixCharacterIndex in item.Property.Indices) + { + if (!_SixCharacterNamedFaceInfo.ContainsKey(sixCharacterIndex)) + continue; + keys = _SixCharacterNamedFaceInfo[sixCharacterIndex]; + _AllCollection.Add(new(item.Property.Id.Value, keys)); + } + } + } + } + + public void SaveAllCollection() + { + if (_AllCollection.Any()) + { + string[] keys; + long ticks = DateTime.Now.Ticks; + string? rootDirectoryParent = Path.GetDirectoryName(_Configuration.RootDirectory); + if (string.IsNullOrEmpty(rootDirectoryParent)) + throw new NullReferenceException(nameof(rootDirectoryParent)); + Dictionary namedFaceInfoDeterministicHashCodeIndices = new(); + List<(int, string[])> allCollection = _AllCollection.OrderBy(l => l.Item1).ToList(); + foreach ((int deterministicHashCode, string[] values) in allCollection) + { + if (namedFaceInfoDeterministicHashCodeIndices.ContainsKey(deterministicHashCode)) + { + keys = namedFaceInfoDeterministicHashCodeIndices[deterministicHashCode]; + if (JsonSerializer.Serialize(values) == JsonSerializer.Serialize(keys)) + continue; + throw new Exception(); + } + namedFaceInfoDeterministicHashCodeIndices.Add(deterministicHashCode, values); + } + string json = JsonSerializer.Serialize(namedFaceInfoDeterministicHashCodeIndices, new JsonSerializerOptions { WriteIndented = true }); + string checkFile = Path.Combine(rootDirectoryParent, "NamedFaceInfoDeterministicHashCodeIndices.json"); + _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: true, compareBeforeWrite: true); + _ = LogDelta(ticks, new StackFrame().GetMethod()?.Name); + } + } + + public static void AddToNamed(MapLogic mapLogic, List items) + { + bool? isWrongYear; + DateTime minimumDateTime; + double deterministicHashCodeKey; + List personKeys = new(); + Shared.Models.PersonBirthday? personBirthday; + foreach (Shared.Models.Item item in items) + { + if (item.ImageFileHolder is null) + continue; + if (item.Property?.Id is null || item.ResizedFileHolder is null) + continue; + foreach (Shared.Models.Face face in item.Faces) + { + personKeys.Clear(); + if (face.LocationIndex is null) + continue; + deterministicHashCodeKey = Shared.Models.Stateless.Methods.INamed.GetDeterministicHashCodeKey(item, face); + if (!mapLogic.NamedDeterministicHashCodeKeyValuePairs.ContainsKey(deterministicHashCodeKey)) + continue; + minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property); + personKeys.AddRange(mapLogic.NamedDeterministicHashCodeKeyValuePairs[deterministicHashCodeKey]); + (isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime); + for (int i = 0; i < personKeys.Count; i++) + { + personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKeys[i]); + if (personBirthday is null) + continue; + if (face.Location is null) + continue; + item.Named.Add(new(isWrongYear, minimumDateTime, face.Location.NormalizedPixelPercentage, personBirthday)); + } + } + if (!personKeys.Any()) + { + if (!mapLogic.NamedFaceInfoDeterministicHashCodeKeyValuePairs.ContainsKey(item.Property.Id.Value)) + continue; + minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property); + personKeys.AddRange(mapLogic.NamedFaceInfoDeterministicHashCodeKeyValuePairs[item.Property.Id.Value]); + (isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime); + for (int i = 0; i < personKeys.Count; i++) + { + personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKeys[i]); + if (personBirthday is null) + continue; + item.Named.Add(new(isWrongYear, minimumDateTime, personBirthday)); + } + } + } + } + + public static List<(Shared.Models.Item, (string, Shared.Models.Face?, (string, string, string, string))[])> GetCollection(MapLogic mapLogic, List items, string dFacesContentDirectory) + { + List<(Shared.Models.Item, (string, Shared.Models.Face?, (string, string, string, string))[])> results = new(); + string[] keys; + string directory; + string personKey; + bool? isWrongYear; + const int zero = 0; + TimeSpan? timeSpan; + string copyFileName; + string copyDirectory; + string? relativePath; + string isWrongYearFlag; + Shared.Models.Face face; + string shortcutFileName; + Shared.Models.Item item; + string subDirectoryName; + List indices = new(); + DateTime? minimumDateTime; + List faceCollection; + Shared.Models.PersonBirthday? personBirthday; + List<(string, Shared.Models.Face?, (string, string, string, string))> collection; + for (int i = 0; i < items.Count; i++) + { + indices.Clear(); + copyFileName = string.Empty; + copyDirectory = string.Empty; + item = items[i]; + if (item.ImageFileHolder is null) + continue; + relativePath = Path.GetDirectoryName($"C:{item.RelativePath}"); + if (string.IsNullOrEmpty(relativePath) || relativePath.Length < 3) + continue; + if (item.Property?.Id is null || item.ResizedFileHolder is null) + continue; + collection = new(); + if (!mapLogic.NamedFaceInfoDeterministicHashCodeKeyValuePairs.ContainsKey(item.Property.Id.Value)) + { + faceCollection = new(); + personKey = string.Empty; + directory = Path.Combine(dFacesContentDirectory, $"Unnamed{relativePath[2..]}"); + } + else + { + faceCollection = item.Faces; + keys = mapLogic.NamedFaceInfoDeterministicHashCodeKeyValuePairs[item.Property.Id.Value]; + minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property); + if (minimumDateTime is null) + continue; + (isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime.Value); + isWrongYearFlag = Shared.Models.Stateless.Methods.IItem.GetWrongYearFlag(isWrongYear); + subDirectoryName = $"{isWrongYearFlag}{minimumDateTime.Value:yyyy}"; + if (!faceCollection.Any()) + { + personKey = string.Empty; + directory = Path.Combine(dFacesContentDirectory, $"None{relativePath[2..]}", subDirectoryName); + } + else if (keys.Length != 1) + { + personKey = string.Empty; + directory = Path.Combine(dFacesContentDirectory, $"Not Supported{relativePath[2..]}", subDirectoryName); + } + else if (faceCollection.Count != 1) + { + personKey = string.Empty; + directory = Path.Combine(dFacesContentDirectory, $"Many{relativePath[2..]}", subDirectoryName); + } + else + { + indices.Add(zero); + personKey = keys[zero]; + personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKey); + if (personBirthday is null) + continue; + timeSpan = Shared.Models.Stateless.Methods.IPersonBirthday.GetTimeSpan(minimumDateTime.Value, isWrongYear, personBirthday); + if (timeSpan.HasValue) + { + if (timeSpan.Value.Ticks < 0) + subDirectoryName = "!---"; + else + subDirectoryName = $"^{Math.Floor(timeSpan.Value.TotalDays / 365):000}"; + } + face = faceCollection[zero]; + directory = Path.Combine(dFacesContentDirectory, "Shortcuts", personKey, subDirectoryName); + if (face.FaceEncoding is not null && face.Location?.NormalizedPixelPercentage is not null) + copyDirectory = Path.Combine(dFacesContentDirectory, "Images", personKey, subDirectoryName); + else + copyDirectory = Path.Combine(dFacesContentDirectory, "ImagesBut", personKey, subDirectoryName); + copyFileName = Path.Combine(copyDirectory, $"{item.Property.Id.Value}{item.ResizedFileHolder.ExtensionLowered}"); + } + } + shortcutFileName = Path.Combine(directory, $"{item.Property.Id.Value}.lnk"); + if (string.IsNullOrEmpty(personKey) || !indices.Any()) + collection.Add(new(personKey, null, (directory, copyDirectory, copyFileName, shortcutFileName))); + else + { + foreach (int index in indices) + collection.Add(new(personKey, faceCollection[index], (directory, copyDirectory, copyFileName, shortcutFileName))); + } + results.Add(new(item, collection.ToArray())); + } + return results; + } + + public static string GetKey(DateTime minimumDateTime, bool? isWrongYear, Shared.Models.PersonBirthday personBirthday) + { + string result; + string personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthday); + TimeSpan? timeSpan = Shared.Models.Stateless.Methods.IPersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday); + if (timeSpan.HasValue && timeSpan.Value.Ticks < 0) + result = string.Concat(personKey, "!---"); + else if (timeSpan.HasValue) + result = string.Concat(personKey, $"^{Math.Floor(timeSpan.Value.TotalDays / 365):000}"); + else + { + string isWrongYearFlag = Shared.Models.Stateless.Methods.IItem.GetWrongYearFlag(isWrongYear); + result = string.Concat(personKey, $"{isWrongYearFlag}{minimumDateTime:yyyy}"); + } + return result; + } + + public static string GetDirectory(string directory, string subDirectory, DateTime minimumDateTime, bool? isWrongYear, Shared.Models.PersonBirthday personBirthday, string personKey) + { + string result; + TimeSpan? timeSpan = Shared.Models.Stateless.Methods.IPersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday); + if (timeSpan.HasValue && timeSpan.Value.Ticks < 0) + result = Path.Combine(directory, subDirectory, personKey, "!---"); + else if (timeSpan.HasValue) + result = Path.Combine(directory, subDirectory, personKey, $"^{Math.Floor(timeSpan.Value.TotalDays / 365):000}"); + else + { + string isWrongYearFlag = Shared.Models.Stateless.Methods.IItem.GetWrongYearFlag(isWrongYear); + result = Path.Combine(directory, subDirectory, personKey, $"{isWrongYearFlag}{minimumDateTime:yyyy}"); + } + return result; + } + + public static Dictionary> GetKeyValuePairs(string argZero, List containers) + { + Dictionary> results = new(); + string key; + foreach (Shared.Models.Container container in containers) + { + if (!container.Items.Any()) + continue; + if (!container.SourceDirectory.StartsWith(argZero)) + continue; + foreach (Shared.Models.Item item in container.Items) + { + if (item.ImageFileHolder is null || item.Property is null || !item.Named.Any()) + continue; + foreach (Shared.Models.Named named in item.Named) + { + if (named.NormalizedPixelPercentage is null && (item.Named.Count != 1 || item.Faces.Count != 1)) + continue; + foreach (Shared.Models.Face face in item.Faces) + { + if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) + continue; + if (named.PersonBirthday is null) + continue; + if (named.NormalizedPixelPercentage.HasValue && named.NormalizedPixelPercentage.Value != face.Location?.NormalizedPixelPercentage) + continue; + key = GetKey(named.MinimumDateTime, named.IsWrongYear, named.PersonBirthday); + if (!results.ContainsKey(key)) + results.Add(key, new()); + results[key].Add(new(named.MinimumDateTime, named.IsWrongYear, named.PersonBirthday, face)); + if (named.NormalizedPixelPercentage is null) + break; + } + } + } + } + return results; + } + + public static (bool?, string[]) IsWrongYear(Shared.Models.Item item) + { + (bool?, string[]) result; + if (item.Property is null || item.ImageFileHolder is null) + throw new NullReferenceException(); + DateTime? minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property); + result = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime); + return result; + } + +} \ No newline at end of file diff --git a/Map/Models/Stateless/SerilogExtensionMethods.cs b/Map/Models/Stateless/SerilogExtensionMethods.cs new file mode 100644 index 0000000..73fa032 --- /dev/null +++ b/Map/Models/Stateless/SerilogExtensionMethods.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Map.Models.Stateless; + +internal static class SerilogExtensionMethods +{ + + internal static void Warn(this Serilog.ILogger log, string messageTemplate) => log.Warning(messageTemplate); + + internal static void Info(this Serilog.ILogger log, string messageTemplate) => log.Information(messageTemplate); + +} \ No newline at end of file diff --git a/Metadata/Metadata.csproj b/Metadata/Metadata.csproj index bd86b21..91c9eaa 100644 --- a/Metadata/Metadata.csproj +++ b/Metadata/Metadata.csproj @@ -10,7 +10,7 @@ Phares.View.by.Distance.Metadata false - 5.0.402.104 + 6.0.100.1 Mike Phares Phares true diff --git a/Metadata/Models/B_Metadata.cs b/Metadata/Models/B_Metadata.cs index 1af9e1d..1e58783 100644 --- a/Metadata/Models/B_Metadata.cs +++ b/Metadata/Models/B_Metadata.cs @@ -78,7 +78,7 @@ public class B_Metadata return results; } - public (int, List>) GetMetadataCollection(string bResultsFullGroupDirectory, List> subFileTuples, List parseExceptions, Property.Models.Item item) + public (int, List>) GetMetadataCollection(string bResultsFullGroupDirectory, List> subFileTuples, List parseExceptions, Shared.Models.Item item) { List> results = new(); if (item.Property?.Id is null) @@ -151,7 +151,7 @@ public class B_Metadata json = JsonSerializer.Serialize(dictionary, _WriteIndentedJsonSerializerOptions); bool updateDateWhenMatches = dateTimes.Any() && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime; DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max(); - if (Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime)) + if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime)) { if (!_ForceMetadataLastWriteTimeToCreationTime && (!fileInfo.Exists || fileInfo.LastWriteTime == fileInfo.CreationTime)) subFileTuples.Add(new Tuple(nameof(B_Metadata), DateTime.Now)); @@ -171,29 +171,4 @@ public class B_Metadata return new(dictionary.Count, results); } - public static List> GetFiltered(List> metadataCollection) - { - List> results = new(); - foreach (KeyValuePair keyValuePair in metadataCollection) - { - if (keyValuePair.Key.Contains("File") || keyValuePair.Key.Contains("JPEG") || keyValuePair.Key.Contains("Orientation") || keyValuePair.Key.Contains("Thumbnail")) - continue; - results.Add(new(keyValuePair.Key, keyValuePair.Value)); - } - if (!results.Any()) - results = metadataCollection; - return results; - } - - public static string GetUniqueImageId(List> metadataCollection) - { - string result = string.Empty; - const string exifSubIFD = "Exif SubIFD"; - const string uniqueImageID = "42016\tUnique Image ID"; - List uniqueImageIDs = (from l in metadataCollection where l.Key.StartsWith(exifSubIFD) && l.Key.EndsWith(uniqueImageID) select l.Value).ToList(); - if (uniqueImageIDs.Any()) - result = uniqueImageIDs[0]; - return result; - } - } \ No newline at end of file diff --git a/Not-Copy-Copy/Not-Copy-Copy.cs b/Not-Copy-Copy/Not-Copy-Copy.cs index 605ee6b..de76fb1 100644 --- a/Not-Copy-Copy/Not-Copy-Copy.cs +++ b/Not-Copy-Copy/Not-Copy-Copy.cs @@ -26,23 +26,22 @@ public class NotCopyCopy _AppSettings = appSettings; _IsEnvironment = isEnvironment; _Log = Serilog.Log.ForContext(); - Property.Models.Configuration propertyConfiguration = Property.Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory); + Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot); Property.Models.Configuration.Verify(propertyConfiguration); Models.Configuration configuration = Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory, propertyConfiguration); Verify(configuration); bool reverse = false; Model? model = null; - PredictorModel? predictorModel = null; + string outputExtension = ".jpg"; _Configuration = configuration; - if (propertyConfiguration.PopulatePropertyId is null) - throw new NullReferenceException(nameof(propertyConfiguration.PopulatePropertyId)); + PredictorModel? predictorModel = null; if (!_IsEnvironment.Development) throw new Exception("This program only allows development environments!"); - PropertyLogic propertyLogic = GetPropertyLogic(reverse, model, predictorModel); + A_Property propertyLogic = GetPropertyLogic(reverse, model, outputExtension, predictorModel); propertyConfiguration.ChangeRootDirectory(configuration.CompareSource); - List compareContainers = Property.Models.Stateless.A_Property.Get(propertyConfiguration, propertyLogic); + List compareContainers = A_Property.Get(propertyConfiguration, propertyLogic); propertyConfiguration.ChangeRootDirectory(configuration.SelectedSource); - List selectedContainers = Property.Models.Stateless.A_Property.Get(propertyConfiguration, propertyLogic); + List selectedContainers = A_Property.Get(propertyConfiguration, propertyLogic); if (compareContainers.Count == selectedContainers.Count) throw new Exception(); string directoryName; @@ -103,12 +102,12 @@ public class NotCopyCopy throw new NullReferenceException(nameof(configuration.SelectedSource)); } - private PropertyLogic GetPropertyLogic(bool reverse, Model? model, PredictorModel? predictorModel) + private A_Property GetPropertyLogic(bool reverse, Model? model, string outputExtension, PredictorModel? predictorModel) { - PropertyLogic result; + A_Property result; if (_Configuration?.PropertyConfiguration is null) throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration)); - result = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, reverse, model, predictorModel); + result = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, outputExtension, reverse, model, predictorModel); return result; } @@ -119,12 +118,12 @@ public class NotCopyCopy throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration)); string key; string fileName; - A_Property? property; + Shared.Models.Property? property; string destinationDirectory; List directoryNames; List destinationCollection; string filteredSourceDirectoryFile; - Dictionary keyValuePairs = new(); + Dictionary keyValuePairs = new(); foreach (Property.Models.DirectoryInfo group in compareSourceGroupCollection) { for (int i = 0; i < group.SourceDirectoryFileHolderCollection.Length; i++) @@ -150,7 +149,7 @@ public class NotCopyCopy if (keyValuePairs.ContainsKey(key) && keyValuePairs[key].LastWriteTime == property.LastWriteTime) continue; destinationDirectory = string.Concat(_Configuration.EmptyDestination, group.SourceDirectory[_Configuration.SelectedSource.Length..]); - directoryNames = Property.Models.Stateless.IPath.GetDirectoryNames(destinationDirectory); + directoryNames = Shared.Models.Stateless.Methods.IPath.GetDirectoryNames(destinationDirectory); destinationCollection.AddRange(directoryNames); destinationCollection.Add(fileName); results.Add(new(filteredSourceDirectoryFile, destinationCollection.ToArray())); diff --git a/Not-Copy-Copy/Not-Copy-Copy.csproj b/Not-Copy-Copy/Not-Copy-Copy.csproj index ebb0038..0876809 100644 --- a/Not-Copy-Copy/Not-Copy-Copy.csproj +++ b/Not-Copy-Copy/Not-Copy-Copy.csproj @@ -10,7 +10,7 @@ Phares.View.by.Distance.Not.Copy.Copy false - 5.0.402.104 + 6.0.100.1 Mike Phares Phares true diff --git a/Not-Copy-Copy/Program.cs b/Not-Copy-Copy/Program.cs index 5df9a03..7ca1a71 100644 --- a/Not-Copy-Copy/Program.cs +++ b/Not-Copy-Copy/Program.cs @@ -39,60 +39,60 @@ public class Program if (args is null) throw new Exception("args is null!"); #nullable disable - if (Property.Models.Stateless.A_Property.IsWrongYear("-".Split(' '), "2021").Item1.HasValue) + if (IProperty.IsWrongYear("-".Split(' '), "2021").Item1.HasValue) throw new Exception("-"); - if (Property.Models.Stateless.A_Property.IsWrongYear("Christmass".Split(' '), "2021").Item1.HasValue) + if (IProperty.IsWrongYear("Christmass".Split(' '), "2021").Item1.HasValue) throw new Exception("Christmass"); - if (Property.Models.Stateless.A_Property.IsWrongYear("Christmass 2021".Split(' '), "2021").Item1.Value) + if (IProperty.IsWrongYear("Christmass 2021".Split(' '), "2021").Item1.Value) throw new Exception("Christmass"); - if (Property.Models.Stateless.A_Property.IsWrongYear("Christmass ~2021".Split(' '), "2021").Item1.Value) + if (IProperty.IsWrongYear("Christmass ~2021".Split(' '), "2021").Item1.Value) throw new Exception("Christmass"); - if (Property.Models.Stateless.A_Property.IsWrongYear("Christmass ~2021.4".Split(' '), "2021").Item1.Value) + if (IProperty.IsWrongYear("Christmass ~2021.4".Split(' '), "2021").Item1.Value) throw new Exception("Christmass"); - if (!Property.Models.Stateless.A_Property.IsWrongYear("Christmass 2021".Split(' '), "2025").Item1.Value) + if (!IProperty.IsWrongYear("Christmass 2021".Split(' '), "2025").Item1.Value) throw new Exception("Christmass"); - if (!Property.Models.Stateless.A_Property.IsWrongYear("Christmass ~2021".Split(' '), "2025").Item1.Value) + if (!IProperty.IsWrongYear("Christmass ~2021".Split(' '), "2025").Item1.Value) throw new Exception("Christmass"); - if (!Property.Models.Stateless.A_Property.IsWrongYear("Christmass ~2021.4".Split(' '), "2025").Item1.Value) + if (!IProperty.IsWrongYear("Christmass ~2021.4".Split(' '), "2025").Item1.Value) throw new Exception("Christmass"); - if (Property.Models.Stateless.A_Property.IsWrongYear("England 2017".Split(' '), "2017").Item1.Value) + if (IProperty.IsWrongYear("England 2017".Split(' '), "2017").Item1.Value) throw new Exception("England"); - if (Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael".Split(' '), "2021").Item1.HasValue) + if (IProperty.IsWrongYear("Logan Michael".Split(' '), "2021").Item1.HasValue) throw new Exception("Logan Michael"); - if (Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael 2021".Split(' '), "2021").Item1.Value) + if (IProperty.IsWrongYear("Logan Michael 2021".Split(' '), "2021").Item1.Value) throw new Exception("Logan Michael"); - if (Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael ~2021".Split(' '), "2021").Item1.Value) + if (IProperty.IsWrongYear("Logan Michael ~2021".Split(' '), "2021").Item1.Value) throw new Exception("Logan Michael"); - if (Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael ~2021.4".Split(' '), "2021").Item1.Value) + if (IProperty.IsWrongYear("Logan Michael ~2021.4".Split(' '), "2021").Item1.Value) throw new Exception("Logan Michael"); - if (!Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael 2021".Split(' '), "2025").Item1.Value) + if (!IProperty.IsWrongYear("Logan Michael 2021".Split(' '), "2025").Item1.Value) throw new Exception("Logan Michael"); - if (!Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael ~2021".Split(' '), "2025").Item1.Value) + if (!IProperty.IsWrongYear("Logan Michael ~2021".Split(' '), "2025").Item1.Value) throw new Exception("Logan Michael"); - if (!Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael ~2021.4".Split(' '), "2025").Item1.Value) + if (!IProperty.IsWrongYear("Logan Michael ~2021.4".Split(' '), "2025").Item1.Value) throw new Exception("Logan Michael"); - if (Property.Models.Stateless.A_Property.IsWrongYear("Logan Michael ~2021.4".Split(' '), "2021").Item2[0] != "~2021.4") + if (IProperty.IsWrongYear("Logan Michael ~2021.4".Split(' '), "2021").Item2[0] != "~2021.4") throw new Exception("Logan Michael"); - if (Property.Models.Stateless.A_Property.IsWrongYear("Chelsea's 2nd Birthday =2014".Split(' '), "2014").Item1.Value) + if (IProperty.IsWrongYear("Chelsea's 2nd Birthday =2014".Split(' '), "2014").Item1.Value) throw new Exception("Chelsea"); #nullable restore - if (Property.Models.Stateless.IPath.GetDirectoryNames(@"C:\Tmp")[0] != @"C:\") + if (IPath.GetDirectoryNames(@"C:\Tmp")[0] != @"C:\") throw new Exception(); - if (Property.Models.Stateless.IPath.GetDirectoryNames(@"C:\Tmp")[1] != "Tmp") + if (IPath.GetDirectoryNames(@"C:\Tmp")[1] != "Tmp") throw new Exception(); - if (Property.Models.Stateless.IPath.GetDirectoryNames(@"C:\Tmp\mike.txt")[1] != "Tmp") + if (IPath.GetDirectoryNames(@"C:\Tmp\mike.txt")[1] != "Tmp") throw new Exception(); - if (Property.Models.Stateless.IPath.GetDirectoryNames(@"C:\Tmp\a.txt")[1] != "Tmp") + if (IPath.GetDirectoryNames(@"C:\Tmp\a.txt")[1] != "Tmp") throw new Exception(); - if (Property.Models.Stateless.IPath.GetDirectoryNames(@"C:\Tmp\Mike\a.txt")[2] != "Mike") + if (IPath.GetDirectoryNames(@"C:\Tmp\Mike\a.txt")[2] != "Mike") throw new Exception(); - if (Property.Models.Stateless.IPath.GetDirectoryNames(@"I:\Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - II\=2010.2 Summer\Dsc_8558.jpg")[0] != @"I:\") + if (IPath.GetDirectoryNames(@"I:\Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - II\=2010.2 Summer\Dsc_8558.jpg")[0] != @"I:\") throw new Exception(); - if (Property.Models.Stateless.IPath.GetDirectoryNames(@"I:\Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - II\=2010.2 Summer\Dsc_8558.jpg")[1] != @"Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - II") + if (IPath.GetDirectoryNames(@"I:\Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - II\=2010.2 Summer\Dsc_8558.jpg")[1] != @"Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - II") throw new Exception(); - if (Property.Models.Stateless.IPath.GetDirectoryNames(@"I:\Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - II\=2010.2 Summer\Dsc_8558.jpg")[2] != @"=2010.2 Summer") + if (IPath.GetDirectoryNames(@"I:\Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - II\=2010.2 Summer\Dsc_8558.jpg")[2] != @"=2010.2 Summer") throw new Exception(); - if (Property.Models.Stateless.IPath.GetDirectoryNames(@"I:\Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - II\=2010.2 Summer")[2] != @"=2010.2 Summer") + if (IPath.GetDirectoryNames(@"I:\Images 2019-06-08 - 34a9240ac28b52da97428d7725153a80a757ee6b - II\=2010.2 Summer")[2] != @"=2010.2 Summer") throw new Exception(); Shared.Models.Console console = new(); NotCopyCopy _ = new(args, isEnvironment, configurationRoot, appSettings, workingDirectory, silentIndex > -1, console); diff --git a/Not-Copy-Copy/appsettings.Development.json b/Not-Copy-Copy/appsettings.Development.json index ec4304c..0c736de 100644 --- a/Not-Copy-Copy/appsettings.Development.json +++ b/Not-Copy-Copy/appsettings.Development.json @@ -50,10 +50,10 @@ "WorkingDirectoryName": "PharesApps", "Windows": { "Configuration": { - "DateGroup": "2022-08-14", + "DateGroup": "2022-08-22", "FileNameDirectorySeparator": ".Z.", "ForcePropertyLastWriteTimeToCreationTime": false, - "MaxImagesInDirectoryForTopLevelFirstPass": 50, + "MaxImagesInDirectoryForTopLevelFirstPass": 10, "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", "PopulatePropertyId": false, "PropertiesChangedForProperty": false, diff --git a/PrepareForOld/PrepareForOld.cs b/PrepareForOld/PrepareForOld.cs index 11b1cdb..ccf77d7 100644 --- a/PrepareForOld/PrepareForOld.cs +++ b/PrepareForOld/PrepareForOld.cs @@ -3,7 +3,6 @@ using Phares.Shared; using System.Text.Json; using System.Text.RegularExpressions; using View_by_Distance.PrepareForOld.Models; -using View_by_Distance.Property.Models; using View_by_Distance.Shared.Models.Methods; namespace View_by_Distance.PrepareForOld; @@ -15,10 +14,10 @@ public class PrepareForOld private readonly AppSettings _AppSettings; private readonly List _Exceptions; private readonly IsEnvironment _IsEnvironment; - private readonly Models.Configuration _Configuration; + private readonly Configuration _Configuration; private readonly List> _FileKeyValuePairs; private readonly List<(string Find, string Replace)> _SpellingFindReplace; - private readonly Dictionary>> _FilePropertiesKeyValuePairs; + private readonly Dictionary>> _FilePropertiesKeyValuePairs; public PrepareForOld(List args, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console) { @@ -34,10 +33,10 @@ public class PrepareForOld _Exceptions = new List(); _Log = Serilog.Log.ForContext(); _FileKeyValuePairs = new List>(); - _FilePropertiesKeyValuePairs = new Dictionary>>(); - Property.Models.Configuration propertyConfiguration = Property.Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory); + _FilePropertiesKeyValuePairs = new Dictionary>>(); + Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot); Property.Models.Configuration.Verify(propertyConfiguration); - Models.Configuration configuration = Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory, propertyConfiguration); + Configuration configuration = Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory, propertyConfiguration); Verify(configuration); if (propertyConfiguration.IgnoreExtensions is null) throw new NullReferenceException(nameof(propertyConfiguration.IgnoreExtensions)); @@ -53,7 +52,7 @@ public class PrepareForOld string[] dbFiles = Directory.GetFiles(propertyConfiguration.RootDirectory, "*.db", SearchOption.AllDirectories); foreach (string dbFile in dbFiles) File.Delete(dbFile); - string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(A_Property), "{}"); + string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(Property.Models.A_Property), "{}"); if (!Directory.Exists(aPropertySingletonDirectory)) throw new Exception(aPropertySingletonDirectory); ConsoleKey? consoleKey = null; @@ -104,7 +103,7 @@ public class PrepareForOld _Configuration = configuration; } - private static void Verify(Models.Configuration configuration) + private static void Verify(Configuration configuration) { if (configuration.Spelling is null || !configuration.Spelling.Any()) throw new NullReferenceException(nameof(configuration.Spelling)); @@ -157,7 +156,7 @@ public class PrepareForOld indexInfoFiles.AddRange(Directory.GetFiles(infoDirectoryExtra, "IndexInfo.json", SearchOption.AllDirectories)); foreach (Models.SaveTabSeparatedValues.ImageExifInfo exifInfo in exifCollection) { - dateTimes = Property.Models.Stateless.A_Property.GetDateTimes(exifInfo.CreationTime, exifInfo.LastWriteTime, exifInfo.DateTime, exifInfo.DateTimeDigitized, exifInfo.DateTimeOriginal, exifInfo.GPSDateStamp); + dateTimes = Shared.Models.Stateless.Methods.IProperty.GetDateTimes(exifInfo.CreationTime, exifInfo.LastWriteTime, exifInfo.DateTime, exifInfo.DateTimeDigitized, exifInfo.DateTimeOriginal, exifInfo.GPSDateStamp); if (!checkDistinct && keyValuePairs.ContainsKey(exifInfo.Index)) continue; keyValuePairs.Add(exifInfo.Index, dateTimes.Min().Ticks); @@ -252,7 +251,7 @@ public class PrepareForOld { long ticks = DateTime.Now.Ticks; string[] lines = (from l in propertyCompareCollection select l.GetSelect()).ToArray(); - string aPropertyCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "[{}]"); + string aPropertyCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(Property.Models.A_Property), "[{}]"); File.WriteAllLines(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.txt"), lines); string json = JsonSerializer.Serialize(propertyCompareCollection, new JsonSerializerOptions { WriteIndented = true }); File.WriteAllText(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.nosj"), json); @@ -611,7 +610,7 @@ public class PrepareForOld { long ticks = DateTime.Now.Ticks; string[] lines = (from l in propertyCompareCollection select l.GetSelect()).ToArray(); - string aPropertyCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "[{}]"); + string aPropertyCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(Property.Models.A_Property), "[{}]"); File.WriteAllLines(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.txt"), lines); string json = JsonSerializer.Serialize(propertyCompareCollection, new JsonSerializerOptions { WriteIndented = true }); File.WriteAllText(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.nosj"), json); diff --git a/PrepareForOld/PrepareForOld.csproj b/PrepareForOld/PrepareForOld.csproj index c4fffbc..a94034b 100644 --- a/PrepareForOld/PrepareForOld.csproj +++ b/PrepareForOld/PrepareForOld.csproj @@ -10,7 +10,7 @@ Phares.View.by.Distance.PrepareForOld false - 5.0.402.104 + 6.0.100.1 Mike Phares Phares true diff --git a/PrepareForOld/appsettings.Development.json b/PrepareForOld/appsettings.Development.json index 3d689be..7df5e14 100644 --- a/PrepareForOld/appsettings.Development.json +++ b/PrepareForOld/appsettings.Development.json @@ -50,11 +50,11 @@ "WorkingDirectoryName": "PharesApps", "Windows": { "Configuration": { - "DateGroup": "2022-08-14", + "DateGroup": "2022-08-22", "FileNameDirectorySeparator": ".Z.", "ForcePropertyLastWriteTimeToCreationTime": false, "KeepFullPath": false, - "MaxImagesInDirectoryForTopLevelFirstPass": 50, + "MaxImagesInDirectoryForTopLevelFirstPass": 10, "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", "PopulatePropertyId": false, "PropertiesChangedForProperty": false, diff --git a/Property-Compare/Models/PropertyCompare.cs b/Property-Compare/Models/PropertyCompare.cs index c07cfc1..40c5b50 100644 --- a/Property-Compare/Models/PropertyCompare.cs +++ b/Property-Compare/Models/PropertyCompare.cs @@ -1,5 +1,4 @@ using System.Text.Json; -using View_by_Distance.Property.Models; namespace View_by_Distance.PropertyCompare.Models; @@ -11,7 +10,7 @@ public partial class PropertyCompare protected readonly bool _IsArg; protected DateTime _MinimumDateTime; protected readonly List _Numbers; - protected A_Property? _Property; + protected Shared.Models.Property? _Property; protected string _RegexResult; protected string _RelativeDirectory; protected readonly List _Strings; @@ -21,12 +20,12 @@ public partial class PropertyCompare public bool IsArg => _IsArg; public DateTime MinimumDateTime => _MinimumDateTime; public List Numbers => _Numbers; - public A_Property? Property => _Property; + public Shared.Models.Property? Property => _Property; public string RegexResult => _RegexResult; public string RelativeDirectory => _RelativeDirectory; public List Strings => _Strings; - public PropertyCompare(string extension, string fileNameWithoutExtension, bool isArg, DateTime minimumDateTime, List numbers, A_Property property, string regexResult, string relativeDirectory, List strings) + public PropertyCompare(string extension, string fileNameWithoutExtension, bool isArg, DateTime minimumDateTime, List numbers, Shared.Models.Property property, string regexResult, string relativeDirectory, List strings) { _IsArg = isArg; _Numbers = numbers; @@ -49,7 +48,7 @@ public partial class PropertyCompare #nullable disable - public string GetSelect() => string.Concat(_RelativeDirectory, _FileNameWithoutExtension, _Extension, '\t', _Property.CreationTime.Ticks, '\t', View_by_Distance.Property.Models.Stateless.A_Property.GetDateTime(_Property).ToString("yyyy-MM-dd_HH-mm-ss"), '\t', _Property.Id, '\t', _Property.FileSize, '\t', _Property.Width, '\t', _Property.Height); + public string GetSelect() => string.Concat(_RelativeDirectory, _FileNameWithoutExtension, _Extension, '\t', _Property.CreationTime.Ticks, '\t', Shared.Models.Stateless.Methods.IProperty.GetDateTime(_Property).ToString("yyyy-MM-dd_HH-mm-ss"), '\t', _Property.Id, '\t', _Property.FileSize, '\t', _Property.Width, '\t', _Property.Height); #nullable restore diff --git a/Property-Compare/Models/PropertyCompareItem.cs b/Property-Compare/Models/PropertyCompareItem.cs index 09e8b70..a78fdfb 100644 --- a/Property-Compare/Models/PropertyCompareItem.cs +++ b/Property-Compare/Models/PropertyCompareItem.cs @@ -1,5 +1,3 @@ -using View_by_Distance.Property.Models; - namespace View_by_Distance.PropertyCompare.Models; internal class PropertyCompareItem @@ -9,16 +7,16 @@ internal class PropertyCompareItem protected readonly bool _IsArg; protected readonly string _JsonFileNameWithoutExtension; protected readonly long[] _Numbers; - protected readonly A_Property _Property; + protected readonly Shared.Models.Property _Property; protected readonly string[] _Strings; public string ImageFileName => _ImageFileName; public bool IsArg => _IsArg; public string JsonFileNameWithoutExtension => _JsonFileNameWithoutExtension; public long[] Numbers => _Numbers; - public A_Property Property => _Property; + public Shared.Models.Property Property => _Property; public string[] Strings => _Strings; - public PropertyCompareItem(string imageFileName, bool isArg, string jsonFileNameWithoutExtension, long[] numbers, A_Property property, string[] strings) + public PropertyCompareItem(string imageFileName, bool isArg, string jsonFileNameWithoutExtension, long[] numbers, Shared.Models.Property property, string[] strings) { _ImageFileName = imageFileName; _IsArg = isArg; diff --git a/Property-Compare/Models/PropertyCompareLogic.cs b/Property-Compare/Models/PropertyCompareLogic.cs index c1124f8..b82e538 100644 --- a/Property-Compare/Models/PropertyCompareLogic.cs +++ b/Property-Compare/Models/PropertyCompareLogic.cs @@ -19,7 +19,7 @@ public class PropertyCompareLogic _Configuration = configuration; _DiffRootDirectory = diffRootDirectory; _SpellingFindReplace = spellingFindReplace; - _Log = Serilog.Log.ForContext(); + _Log = Serilog.Log.ForContext(); _MaxDegreeOfParallelism = Math.Abs(maxDegreeOfParallelism); } @@ -175,10 +175,10 @@ public class PropertyCompareLogic else extension = Path.GetExtension(files[index]); string json = File.ReadAllText(jsonFile); - A_Property? property = JsonSerializer.Deserialize(json); + Shared.Models.Property? property = JsonSerializer.Deserialize(json); if (property?.Id is null) throw new NullReferenceException(nameof(property)); - DateTime minimumDateTime = Property.Models.Stateless.A_Property.GetMinimumDateTime(property); + DateTime minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(property); corrected = string.Concat(relativeDirectory, jsonFileNameWithoutExtension); if (_SpellingFindReplace is not null && (from l in _SpellingFindReplace where corrected.Contains(l.Find) select true).Any()) { @@ -200,17 +200,17 @@ public class PropertyCompareLogic 2 => property.Id.Value, 3 => property.Id.Value, 4 => property.Id.Value, - 5 => Property.Models.Stateless.A_Property.GetDateTime(property).Ticks, + 5 => Shared.Models.Stateless.Methods.IProperty.GetDateTime(property).Ticks, 6 => property.CreationTime.Ticks, 7 => property.FileSize, - 8 => Property.Models.Stateless.A_Property.GetDateTime(property).Ticks, + 8 => Shared.Models.Stateless.Methods.IProperty.GetDateTime(property).Ticks, 9 => property.FileSize, _ => throw new Exception() }; s = i switch { 0 => $"{jsonFileNameWithoutExtension.ToLower()}", - 1 => $"{property.FileSize}{Property.Models.Stateless.A_Property.GetDateTime(property).Ticks}", + 1 => $"{property.FileSize}{Shared.Models.Stateless.Methods.IProperty.GetDateTime(property).Ticks}", 2 => $"{property.FileSize}{property.CreationTime:yyyy-MM-dd_HH-mm-ss}", 3 => $"{property.FileSize}{property.Width}{property.Height}", 4 => string.Empty, @@ -313,7 +313,7 @@ public class PropertyCompareLogic } if (exceptionCount != 0) throw new Exception(); - return (from l in results orderby Property.Models.Stateless.A_Property.GetMinimumDateTime(l.Property).Ticks select l).ToArray(); + return (from l in results orderby Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(l.Property).Ticks select l).ToArray(); } private void MoveFiles(string[] directories, List fromThenToCollection) diff --git a/Property-Compare/Property-Compare.csproj b/Property-Compare/Property-Compare.csproj index 4c044a8..9dbbf7e 100644 --- a/Property-Compare/Property-Compare.csproj +++ b/Property-Compare/Property-Compare.csproj @@ -10,7 +10,7 @@ Phares.View.by.Distance.Property.Compare false - 5.0.402.104 + 6.0.100.1 Mike Phares Phares true diff --git a/Property/Models/A_Property.cs b/Property/Models/A_Property.cs index ea8640b..a2c9dbd 100644 --- a/Property/Models/A_Property.cs +++ b/Property/Models/A_Property.cs @@ -1,84 +1,62 @@ +using ShellProgressBar; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Text; using System.Text.Json; -using System.Text.Json.Serialization; -using View_by_Distance.Shared.Models.Methods; +using View_by_Distance.Property.Models.Stateless; +using View_by_Distance.Shared.Models; +using View_by_Distance.Shared.Models.Properties; +using View_by_Distance.Shared.Models.Stateless; namespace View_by_Distance.Property.Models; -/// -// A_Property -/// -public class A_Property : Shared.Models.Properties.IProperty, IProperty +public class A_Property { - protected DateTime _CreationTime; - protected DateTime? _DateTime; - protected DateTime? _DateTimeDigitized; - protected DateTime? _DateTimeOriginal; - protected long _FileSize; - protected DateTime? _GPSDateStamp; - protected int? _Height; - protected int? _Id; - protected int[] _Indices; - protected DateTime _LastWriteTime; - protected string _Make; - protected string _Model; - protected string _Orientation; - protected int? _Width; - public DateTime CreationTime => _CreationTime; - public DateTime? DateTime => _DateTime; - public DateTime? DateTimeDigitized => _DateTimeDigitized; - public DateTime? DateTimeOriginal => _DateTimeOriginal; - public long FileSize => _FileSize; - public DateTime? GPSDateStamp => _GPSDateStamp; - public int? Height => _Height; - public int? Id => _Id; - public int[] Indices => _Indices; - public DateTime LastWriteTime => _LastWriteTime; - public string Make => _Make; - public string Model => _Model; - public string Orientation => _Orientation; - public int? Width => _Width; + protected readonly List _ExceptionsDirectories; + protected readonly Dictionary _KeyValuePairs; + protected readonly Dictionary _IndicesFromNew; - [JsonConstructor] - public A_Property(DateTime creationTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeOriginal, long fileSize, DateTime? gpsDateStamp, int? height, int? id, int[] indices, DateTime lastWriteTime, string make, string model, string orientation, int? width) + public bool Reverse { get; } + public List AngleBracketCollection { get; } + public List ExceptionsDirectories => _ExceptionsDirectories; + + private readonly Model? _Model; + private readonly Serilog.ILogger? _Log; + private readonly string _OutputExtension; + private readonly string[] _VerifyToSeason; + private readonly int _MaxDegreeOfParallelism; + private readonly ASCIIEncoding _ASCIIEncoding; + private readonly Configuration _Configuration; + private readonly PredictorModel? _PredictorModel; + private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; + + public A_Property(int maxDegreeOfParallelism, Configuration configuration, string outputExtension, bool reverse, Model? model, PredictorModel? predictorModel, Dictionary indicesFromNew, Dictionary keyValuePairs) { - _CreationTime = creationTime; - _DateTime = dateTime; - _DateTimeDigitized = dateTimeDigitized; - _DateTimeOriginal = dateTimeOriginal; - _FileSize = fileSize; - _GPSDateStamp = gpsDateStamp; - _Height = height; - _Id = id; - _Indices = indices; - _LastWriteTime = lastWriteTime; - _Make = make; _Model = model; - _Orientation = orientation; - _Width = width; + Reverse = reverse; + _KeyValuePairs = keyValuePairs; + _Configuration = configuration; + _ExceptionsDirectories = new(); + _IndicesFromNew = indicesFromNew; + _PredictorModel = predictorModel; + _OutputExtension = outputExtension; + _ASCIIEncoding = new ASCIIEncoding(); + AngleBracketCollection = new List(); + _Log = Serilog.Log.ForContext(); + _MaxDegreeOfParallelism = maxDegreeOfParallelism; + _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; + if (configuration.VerifyToSeason is null || !configuration.VerifyToSeason.Any()) + throw new Exception(); + _VerifyToSeason = configuration.VerifyToSeason.Select(l => Path.Combine(configuration.RootDirectory, l)).ToArray(); } -#nullable disable - - public A_Property() - { - _CreationTime = System.DateTime.MinValue; - _DateTime = null; - _DateTimeDigitized = null; - _DateTimeOriginal = null; - _FileSize = long.MinValue; - _GPSDateStamp = null; - _Height = null; - _Id = null; - _Indices = Array.Empty(); - _LastWriteTime = System.DateTime.MinValue; - _Make = string.Empty; - _Model = string.Empty; - _Orientation = string.Empty; - _Width = null; - } - -#nullable restore + public A_Property(int maxDegreeOfParallelism, Configuration configuration, string outputExtension, bool reverse, Model? model, PredictorModel? predictorModel) : + this(maxDegreeOfParallelism, configuration, outputExtension, reverse, model, predictorModel, new(), new()) + { } public override string ToString() { @@ -86,38 +64,658 @@ public class A_Property : Shared.Models.Properties.IProperty, IProperty return result; } - public List GetDateTimes() => Stateless.A_Property.GetDateTimes(_CreationTime, _LastWriteTime, _DateTime, _DateTimeDigitized, _DateTimeOriginal, _GPSDateStamp); - - public (bool?, string[]) IsWrongYear(string filteredSourceDirectoryFile, DateTime? minimumDateTime) + private long LogDelta(long ticks, string? methodName) { - string[] results = Array.Empty(); - bool? result = null; - string year; - string directoryName; - string[] directorySegments; - string? check = Path.GetFullPath(filteredSourceDirectoryFile); - string? pathRoot = Path.GetPathRoot(filteredSourceDirectoryFile); - if (string.IsNullOrEmpty(pathRoot)) - throw new Exception(); - if (minimumDateTime.HasValue) - year = minimumDateTime.Value.ToString("yyyy"); + long result; + if (_Log is null) + throw new NullReferenceException(nameof(_Log)); + double delta = new TimeSpan(DateTime.Now.Ticks - ticks).TotalMilliseconds; + _Log.Debug($"{methodName} took {Math.Floor(delta)} millisecond(s)"); + result = DateTime.Now.Ticks; + return result; + } + + public static List GetMetadataDateTimesByPattern(string dateTimeFormat, string filteredSourceDirectoryFile) + { + List results = new(); + try + { + DateTime checkDateTime; + DateTime kristy = new(1976, 3, 8); + IReadOnlyList directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(filteredSourceDirectoryFile); + foreach (MetadataExtractor.Directory directory in directories) + { + foreach (MetadataExtractor.Tag tag in directory.Tags) + { + if (string.IsNullOrEmpty(tag.Description) || tag.Description.Length != dateTimeFormat.Length) + continue; + if (!DateTime.TryParseExact(tag.Description, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) + continue; + if (checkDateTime < kristy) + continue; + results.Add(checkDateTime); + } + } + } + catch (Exception) { } + return results; + } + + public static List GetMetadataDateTimesByPattern(string dateTimeFormat, IFileHolder filteredSourceDirectoryFileHolder) + { + List results = GetMetadataDateTimesByPattern(dateTimeFormat, filteredSourceDirectoryFileHolder.FullName); + return results; + } + +#pragma warning disable CA1416 + + private Shared.Models.Property GetImageProperty(IFileHolder filteredSourceDirectoryFileHolder, bool populateId, bool isIgnoreExtension, bool isValidImageFormatExtension, bool isValidMetadataExtensions, int? id, List indices) + { + Shared.Models.Property result; + if (_Log is null) + throw new NullReferenceException(nameof(_Log)); + long ticks; + byte[] bytes; + string value; + long fileLength; + int encodingHash; + int? width = null; + int? height = null; + string dateTimeFormat; + DateTime checkDateTime; + DateTime? dateTime = null; + PropertyItem? propertyItem; + string make = string.Empty; + string model = string.Empty; + DateTime? gpsDateStamp = null; + DateTime? dateTimeOriginal = null; + string orientation = string.Empty; + DateTime? dateTimeDigitized = null; + if (!isValidImageFormatExtension && isValidMetadataExtensions) + { + dateTimeFormat = "ddd MMM dd HH:mm:ss yyyy"; + List dateTimes = GetMetadataDateTimesByPattern(dateTimeFormat, filteredSourceDirectoryFileHolder); + if (dateTimes.Any()) + dateTimeOriginal = dateTimes.Min(); + } + else if (!isIgnoreExtension && isValidImageFormatExtension) + { + if (populateId && (id is null || !indices.Any()) && !_IndicesFromNew.Any() && !_KeyValuePairs.Any()) + throw new Exception("In order to keep six character indices at least one need to have an item!"); + try + { + using Image image = Image.FromFile(filteredSourceDirectoryFileHolder.FullName); + if (populateId && (id is null || !indices.Any())) + { + using Bitmap bitmap = new(image); + string angleBracket = AngleBracketCollection[0]; + Rectangle rectangle = new(0, 0, image.Width, image.Height); + BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat); + IntPtr intPtr = bitmapData.Scan0; + int length = bitmapData.Stride * bitmap.Height; + bytes = new byte[length]; + Marshal.Copy(intPtr, bytes, 0, length); + bitmap.UnlockBits(bitmapData); + if (id is null) + { + ticks = DateTime.Now.Ticks; + id = Shared.Models.Stateless.Methods.IProperty.GetDeterministicHashCode(bytes); + if (_MaxDegreeOfParallelism < 2) + ticks = LogDelta(ticks, nameof(Shared.Models.Stateless.Methods.IProperty.GetDeterministicHashCode)); + } + if (_Configuration.WriteBitmapDataBytes) + { + FileInfo contentFileInfo = new(Path.Combine(angleBracket.Replace("<>", "()"), filteredSourceDirectoryFileHolder.Name)); + File.WriteAllBytes(Path.ChangeExtension(contentFileInfo.FullName, string.Empty), bytes); + } + if (_IndicesFromNew.ContainsKey(id.Value) && _IndicesFromNew[id.Value].Any()) + indices.AddRange(_IndicesFromNew[id.Value]); + else + { + ticks = DateTime.Now.Ticks; + string encoding = Encoding.Default.GetString(bytes); + if (_MaxDegreeOfParallelism < 2) + ticks = LogDelta(ticks, nameof(Encoding.Default.GetString)); + encodingHash = Shared.Models.Stateless.Methods.IProperty.GetDeterministicHashCode(encoding); + if (_MaxDegreeOfParallelism < 2) + ticks = LogDelta(ticks, nameof(Shared.Models.Stateless.Methods.IProperty.GetDeterministicHashCode)); + if (!_KeyValuePairs.ContainsKey(encodingHash)) + indices.Add(encodingHash); + else + indices.AddRange(_KeyValuePairs[encodingHash]); + } + } + width = image.Width; + height = image.Height; + dateTimeFormat = Shared.Models.Stateless.Methods.IProperty.DateTimeFormat(); + if (image.PropertyIdList.Contains((int)IExif.Tags.DateTime)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTime); + if (propertyItem?.Value is not null) + { + value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + if (value.Length > dateTimeFormat.Length) + value = value[..dateTimeFormat.Length]; + if (value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) + dateTime = checkDateTime; + } + } + if (image.PropertyIdList.Contains((int)IExif.Tags.DateTimeDigitized)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTimeDigitized); + if (propertyItem?.Value is not null) + { + value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + if (value.Length > dateTimeFormat.Length) + value = value[..dateTimeFormat.Length]; + if (value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) + dateTimeDigitized = checkDateTime; + } + } + if (image.PropertyIdList.Contains((int)IExif.Tags.DateTimeOriginal)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTimeOriginal); + if (propertyItem?.Value is not null) + { + value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + if (value.Length > dateTimeFormat.Length) + value = value[..dateTimeFormat.Length]; + if (value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) + dateTimeOriginal = checkDateTime; + } + } + if (image.PropertyIdList.Contains((int)IExif.Tags.GPSDateStamp)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.GPSDateStamp); + if (propertyItem?.Value is not null) + { + value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + if (value.Length > dateTimeFormat.Length) + value = value[..dateTimeFormat.Length]; + if (value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) + gpsDateStamp = checkDateTime; + } + } + if (image.PropertyIdList.Contains((int)IExif.Tags.Make)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.Make); + if (propertyItem?.Value is not null) + { + value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + make = value; + } + } + if (image.PropertyIdList.Contains((int)IExif.Tags.Model)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.Model); + if (propertyItem?.Value is not null) + { + value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); + model = value; + } + } + if (image.PropertyIdList.Contains((int)IExif.Tags.Orientation)) + { + propertyItem = image.GetPropertyItem((int)IExif.Tags.Orientation); + if (propertyItem?.Value is not null) + { + value = BitConverter.ToInt16(propertyItem.Value, 0).ToString(); + orientation = value; + } + } + } + catch (Exception) + { + _Log.Info(string.Concat(new StackFrame().GetMethod()?.Name, " <", filteredSourceDirectoryFileHolder.Name, ">")); + } + } + else + dateTimeOriginal = null; + if (filteredSourceDirectoryFileHolder.Length is null) + fileLength = 0; + else + fileLength = filteredSourceDirectoryFileHolder.Length.Value; + result = new(filteredSourceDirectoryFileHolder.CreationTime, dateTime, dateTimeDigitized, dateTimeOriginal, fileLength, gpsDateStamp, height, id, indices.ToArray(), filteredSourceDirectoryFileHolder.LastWriteTime, make, model, orientation, width); + return result; + } + +#pragma warning restore CA1416 + + private Shared.Models.Property GetPropertyOfPrivate(Item item, bool firstPass, List> filteredSourceDirectoryFileTuples, List parseExceptions, bool isIgnoreExtension, bool isValidMetadataExtensions) + { + Shared.Models.Property? result; + if (item.ImageFileHolder is null) + throw new NullReferenceException(nameof(item.ImageFileHolder)); + string json; + int? id = null; + List indices = new(); + bool hasWrongYearProperty = false; + string[] changesFrom = Array.Empty(); + string angleBracket = AngleBracketCollection[0]; + bool populateId = !firstPass && _Configuration.PopulatePropertyId; + string without = Path.Combine(angleBracket.Replace("<>", "{}"), $"{item.ImageFileHolder.NameWithoutExtension}.json"); + FileInfo fileInfo = new(Path.Combine(angleBracket.Replace("<>", "{}"), $"{item.ImageFileHolder.NameWithoutExtension}{item.ImageFileHolder.ExtensionLowered}.json")); + if (item.ValidImageFormatExtension && File.Exists(without)) + { + File.Move(without, fileInfo.FullName); + fileInfo.Refresh(); + } + List dateTimes = (from l in filteredSourceDirectoryFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); + if (!fileInfo.Exists) + { + if (fileInfo.Directory?.Parent is null) + throw new Exception(); + string parentCheck = Path.Combine(fileInfo.Directory.Parent.FullName, fileInfo.Name); + if (File.Exists(parentCheck)) + { + File.Move(parentCheck, fileInfo.FullName); + fileInfo.Refresh(); + } + } + if (_Configuration.ForcePropertyLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete"))) + { + File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName); + fileInfo.Refresh(); + } + if (_Configuration.ForcePropertyLastWriteTimeToCreationTime && fileInfo.Exists && fileInfo.LastWriteTime != fileInfo.CreationTime) + { + File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime); + fileInfo.Refresh(); + } + if (_Configuration.PropertiesChangedForProperty) + result = null; + else if (!fileInfo.Exists) + result = null; + else if (!fileInfo.FullName.EndsWith(".json") && !fileInfo.FullName.EndsWith(".old")) + throw new ArgumentException("must be a *.json file"); + else if (dateTimes.Any() && dateTimes.Max() > fileInfo.LastWriteTime) + result = null; else { - List dateTimes = GetDateTimes(); - year = dateTimes.Min().ToString("yyyy"); + json = File.ReadAllText(fileInfo.FullName); + try + { + if (item.ImageFileHolder is null) + throw new NullReferenceException(nameof(item.ImageFileHolder)); + bool check = true; + Shared.Models.Property? property = JsonSerializer.Deserialize(json); + if (!isIgnoreExtension && item.ValidImageFormatExtension && ((populateId && property?.Id is null) || property?.Width is null || property?.Height is null)) + { + check = false; + id = property?.Id; + if (property is not null && property.Indices.Any()) + indices = property.Indices.ToList(); + property = GetImageProperty(item.ImageFileHolder, populateId, isIgnoreExtension, item.ValidImageFormatExtension, isValidMetadataExtensions, id, indices); + } + if (!isIgnoreExtension && item.ValidImageFormatExtension && populateId && property is not null && !property.Indices.Any()) + { + check = false; + id = property?.Id; + if (property is not null && property.Indices.Any()) + indices = property.Indices.ToList(); + property = GetImageProperty(item.ImageFileHolder, populateId, isIgnoreExtension, item.ValidImageFormatExtension, isValidMetadataExtensions, id, indices); + } + if (!isIgnoreExtension && item.ValidImageFormatExtension && populateId && property is not null && property.LastWriteTime != item.ImageFileHolder.LastWriteTime) + { + check = false; + id = null; + indices.Clear(); + property = GetImageProperty(item.ImageFileHolder, populateId, isIgnoreExtension, item.ValidImageFormatExtension, isValidMetadataExtensions, id, indices); + } + if (!isIgnoreExtension && item.ValidImageFormatExtension && property?.Width is not null && property?.Height is not null && property.Width.Value == property.Height.Value && item.ImageFileHolder.Exists) + { + check = false; + id = property?.Id; + if (property is not null && property.Indices.Any()) + indices = property.Indices.ToList(); + property = GetImageProperty(item.ImageFileHolder, populateId, isIgnoreExtension, item.ValidImageFormatExtension, isValidMetadataExtensions, id, indices); + if (property?.Width is not null && property?.Height is not null && property.Width.Value != property.Height.Value) + throw new Exception("Was square!"); + } + // if (filteredSourceDirectoryFileFileInfo.CreationTime != property?.CreationTime || filteredSourceDirectoryFileFileInfo.LastWriteTime != property?.LastWriteTime) + // { + // check = false; + // id = null; + // indices.Clear(); + // property = GetImagePropertyB(filteredSourceDirectoryFile, populateId, isIgnoreExtension, isValidImageFormatExtension, isValidMetadataExtensions, id, indices); + // } + if (json.Contains("WrongYear")) + { + id = property?.Id; + hasWrongYearProperty = true; + } + if (property is null) + throw new Exception(); + if (!check) + result = null; + else + { + result = property; + filteredSourceDirectoryFileTuples.Add(new Tuple(nameof(A_Property), fileInfo.LastWriteTime)); + } + } + catch (Exception) + { + result = null; + parseExceptions.Add(nameof(A_Property)); + } } - for (int i = 0; i < int.MaxValue; i++) + if (result is null) { - check = Path.GetDirectoryName(check); - if (string.IsNullOrEmpty(check) || check == pathRoot) - break; - directoryName = Path.GetFileName(check); - directorySegments = directoryName.Split(' '); - (result, results) = Stateless.A_Property.IsWrongYear(directorySegments, year); - if (result.HasValue) - break; + if (item.ImageFileHolder is null) + throw new NullReferenceException(nameof(item.ImageFileHolder)); + result = GetImageProperty(item.ImageFileHolder, populateId, isIgnoreExtension, item.ValidImageFormatExtension, isValidMetadataExtensions, id, indices); + json = JsonSerializer.Serialize(result, _WriteIndentedJsonSerializerOptions); + if (populateId && Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true)) + { + if (!_Configuration.ForcePropertyLastWriteTimeToCreationTime && (!fileInfo.Exists || fileInfo.LastWriteTime == fileInfo.CreationTime)) + filteredSourceDirectoryFileTuples.Add(new Tuple(nameof(A_Property), DateTime.Now)); + else + { + File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime); + fileInfo.Refresh(); + filteredSourceDirectoryFileTuples.Add(new Tuple(nameof(A_Property), fileInfo.CreationTime)); + } + } } - return new(result, results); + else if (hasWrongYearProperty) + { + json = JsonSerializer.Serialize(result, _WriteIndentedJsonSerializerOptions); + if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true)) + { + File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime); + fileInfo.Refresh(); + filteredSourceDirectoryFileTuples.Add(new Tuple(nameof(A_Property), fileInfo.CreationTime)); + } + } + return result; + } + + private bool AnyFilesMoved(string sourceDirectory, Item[] filteredItems) + { + bool result = false; + if (_Log is null) + throw new NullReferenceException(nameof(_Log)); + int season; + string[] matches; + string deleteFile; + bool? isWrongYear; + string seasonName; + DateTime dateTime; + string destinationFile; + DateTime minimumDateTime; + string destinationDirectory; + string[] sourceDirectorySegments; + DateTime directoryMaximumOfMinimumDateTime = DateTime.MinValue; + foreach (Item filteredItem in filteredItems) + { + if (!filteredItem.ValidImageFormatExtension || filteredItem.Property is null || filteredItem.ImageFileHolder is null) + continue; + minimumDateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(filteredItem.Property); + if (minimumDateTime > directoryMaximumOfMinimumDateTime) + directoryMaximumOfMinimumDateTime = minimumDateTime; + if (minimumDateTime != filteredItem.ImageFileHolder.CreationTime) + { + (isWrongYear, matches) = Shared.Models.Stateless.Methods.IProperty.IsWrongYear(filteredItem.ImageFileHolder.FullName, minimumDateTime); + if (isWrongYear is null || !isWrongYear.Value) + dateTime = minimumDateTime; + else + { + if (!matches.Any()) + continue; + if (!DateTime.TryParseExact(matches[0], "yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + continue; + } + try + { File.SetCreationTime(filteredItem.ImageFileHolder.FullName, dateTime); } + catch (Exception) + { } + } + if (!_VerifyToSeason.Contains(sourceDirectory)) + continue; + if (!filteredItem.ImageFileHolder.FullName.Contains("zzz ") && !filteredItem.ImageFileHolder.FullName.Contains("Camera ") && filteredItem.Property.DateTimeOriginal.HasValue) + { + TimeSpan timeSpan = new(filteredItem.Property.DateTimeOriginal.Value.Ticks - filteredItem.Property.LastWriteTime.Ticks); + if (timeSpan.TotalHours > 6) + { + _Log.Warning($"*** propertyHolder.FileInfo.FullName <{filteredItem.ImageFileHolder.FullName}>"); + _Log.Warning($"*** DateTimeOriginal <{filteredItem.Property.DateTimeOriginal.Value}>"); + _Log.Warning($"*** LastWriteTime <{filteredItem.Property.LastWriteTime}>"); + _Log.Warning($"*** TotalHours <{timeSpan.TotalHours}>"); + } + } + sourceDirectorySegments = Path.GetFileName(sourceDirectory).Split(' '); + (season, seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(minimumDateTime.DayOfYear); + if (sourceDirectorySegments[0] == "zzz") + destinationDirectory = Path.Combine(_Configuration.RootDirectory, $"zzz ={minimumDateTime:yyyy}.{season} {seasonName} {string.Join(' ', sourceDirectorySegments.Skip(3))}"); + else if (sourceDirectorySegments.Length > 2) + destinationDirectory = Path.Combine(_Configuration.RootDirectory, $"={minimumDateTime:yyyy}.{season} {seasonName} {string.Join(' ', sourceDirectorySegments.Skip(2))}"); + else + destinationDirectory = Path.Combine(_Configuration.RootDirectory, $"={minimumDateTime:yyyy}.{season} {seasonName}"); + if (destinationDirectory == sourceDirectory) + continue; + lock (filteredItem) + filteredItem.SetMoved(true); + if (!result) + result = true; + if (!Directory.Exists(destinationDirectory)) + _ = Directory.CreateDirectory(destinationDirectory); + destinationFile = Path.Combine(destinationDirectory, filteredItem.ImageFileHolder.Name); + if (File.Exists(destinationFile)) + { + if (_OutputExtension is not ".jpg" and not ".jpeg") + throw new Exception(); + if (destinationFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture)) + destinationFile = Path.Combine(destinationDirectory, Path.ChangeExtension(filteredItem.ImageFileHolder.Name, ".jpeg")); + else if (destinationFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture)) + destinationFile = Path.Combine(destinationDirectory, Path.ChangeExtension(filteredItem.ImageFileHolder.Name, ".jpg")); + } + if (File.Exists(destinationFile)) + { + _Log.Information($"*** source <{filteredItem.ImageFileHolder.FullName}>"); + _Log.Information($"*** destination <{destinationFile}>"); + if (filteredItem.ImageFileHolder.Exists) + { + deleteFile = Path.ChangeExtension(filteredItem.ImageFileHolder.FullName, ".delete"); + if (File.Exists(deleteFile)) + File.Delete(deleteFile); + File.Move(filteredItem.ImageFileHolder.FullName, deleteFile); + } + } + else + { + File.Move(filteredItem.ImageFileHolder.FullName, destinationFile); + if (filteredItem.ImageFileHolder.Exists) + { + deleteFile = Path.ChangeExtension(filteredItem.ImageFileHolder.FullName, ".delete"); + if (File.Exists(deleteFile)) + File.Delete(deleteFile); + File.Move(filteredItem.ImageFileHolder.FullName, deleteFile); + } + } + } + if (directoryMaximumOfMinimumDateTime != DateTime.MinValue) + { + System.IO.DirectoryInfo directoryInfo = new(sourceDirectory); + if (directoryInfo.LastWriteTime != directoryMaximumOfMinimumDateTime) + Directory.SetLastWriteTime(sourceDirectory, directoryMaximumOfMinimumDateTime); + } + return result; + } + + private void ParallelForWork(bool firstPass, string sourceDirectory, List> filteredSourceDirectoryFileTuples, List> sourceDirectoryChanges, Item item) + { + if (item.ImageFileHolder is null) + throw new NullReferenceException(nameof(item.ImageFileHolder)); + Shared.Models.Property property; + List parseExceptions = new(); + bool isValidMetadataExtensions = _Configuration.ValidMetadataExtensions.Contains(item.ImageFileHolder.ExtensionLowered); + bool isIgnoreExtension = item.ValidImageFormatExtension && _Configuration.IgnoreExtensions.Contains(item.ImageFileHolder.ExtensionLowered); + string filteredSourceDirectoryFileExtensionLowered = Path.Combine(sourceDirectory, $"{item.ImageFileHolder.NameWithoutExtension}{item.ImageFileHolder.ExtensionLowered}"); + if (item.ValidImageFormatExtension && item.ImageFileHolder.FullName.Length == filteredSourceDirectoryFileExtensionLowered.Length && item.ImageFileHolder.FullName != filteredSourceDirectoryFileExtensionLowered) + File.Move(item.ImageFileHolder.FullName, filteredSourceDirectoryFileExtensionLowered); + if (item.Changed is null || item.Changed.Value || item.Property is null) + { + property = GetPropertyOfPrivate(item, firstPass, filteredSourceDirectoryFileTuples, parseExceptions, isIgnoreExtension, isValidMetadataExtensions); + lock (sourceDirectoryChanges) + sourceDirectoryChanges.Add(new Tuple(nameof(A_Property), DateTime.Now)); + lock (item) + item.Update(property); + } + } + + private void ParallelWork(bool firstPass, List exceptions, List> sourceDirectoryChanges, int containersCount, Shared.Models.Container container, Item[] filteredItems, int totalSeconds) + { + List> filteredSourceDirectoryFileTuples = new(); + ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = _MaxDegreeOfParallelism }; + ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; + string message = $"{container.R:000}.{container.G} / {containersCount:000}) {filteredItems.Length:000} file(s) - {totalSeconds} total second(s) - {container.SourceDirectory}"; + using ProgressBar progressBar = new(filteredItems.Length, message, options); + _ = Parallel.For(0, filteredItems.Length, parallelOptions, i => + { + try + { + long ticks = DateTime.Now.Ticks; + DateTime dateTime = DateTime.Now; + List> collection; + ParallelForWork(firstPass, container.SourceDirectory, sourceDirectoryChanges, filteredSourceDirectoryFileTuples, filteredItems[i]); + if (i == 0 || sourceDirectoryChanges.Any()) + progressBar.Tick(); + lock (filteredSourceDirectoryFileTuples) + collection = (from l in filteredSourceDirectoryFileTuples where l.Item2 > dateTime select l).ToList(); + lock (sourceDirectoryChanges) + sourceDirectoryChanges.AddRange(collection); + } + catch (Exception ex) + { + lock (exceptions) + exceptions.Add(ex); + } + }); + } + + private void SetAngleBracketCollection(string sourceDirectory) + { + AngleBracketCollection.Clear(); + AngleBracketCollection.AddRange(IResult.GetDirectoryInfoCollection(_Configuration, + _Model, + _PredictorModel, + sourceDirectory, + nameof(A_Property), + string.Empty, + includeResizeGroup: false, + includeModel: false, + includePredictorModel: false, + contentDescription: string.Empty, + singletonDescription: "Properties for each image", + collectionDescription: string.Empty)); + } + + public void ParallelWork(long ticks, List containers, bool firstPass) + { + if (_Log is null) + throw new NullReferenceException(nameof(_Log)); + int totalSeconds; + bool? anyFilesMoved; + Item[] filteredItems; + List exceptions = new(); + int containersCount = containers.Count; + List> sourceDirectoryChanges = new(); + string propertyRoot = IResult.GetResultsGroupDirectory(_Configuration, nameof(A_Property)); + foreach (Shared.Models.Container container in containers) + { + if (!container.Items.Any()) + continue; + sourceDirectoryChanges.Clear(); + if (firstPass) + filteredItems = (from l in container.Items where l.NoJson is null || !l.NoJson.Value && (l.Changed is null || l.Changed.Value) select l).ToArray(); + else + filteredItems = (from l in container.Items where l.ImageFileHolder is not null && !_Configuration.IgnoreExtensions.Contains(l.ImageFileHolder.ExtensionLowered) select l).ToArray(); + if (!filteredItems.Any()) + continue; + totalSeconds = (int)Math.Truncate(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); + SetAngleBracketCollection(container.SourceDirectory); + ParallelWork(firstPass, exceptions, sourceDirectoryChanges, containersCount, container, filteredItems, totalSeconds); + foreach (Exception exception in exceptions) + _Log.Error(string.Concat(container.SourceDirectory, Environment.NewLine, exception.Message, Environment.NewLine, exception.StackTrace), exception); + if (exceptions.Count == filteredItems.Length) + throw new Exception(string.Concat("All in [", container.SourceDirectory, "]failed!")); + if (exceptions.Count != 0) + _ExceptionsDirectories.Add(container.SourceDirectory); + if (!firstPass || exceptions.Count != 0) + anyFilesMoved = null; + else + anyFilesMoved = AnyFilesMoved(container.SourceDirectory, filteredItems); + if (Directory.GetFiles(propertyRoot, "*.txt", SearchOption.TopDirectoryOnly).Any()) + { + for (int y = 0; y < int.MaxValue; y++) + { + _Log.Information("Press \"Y\" key when ready to continue or close console"); + if (System.Console.ReadKey().Key == ConsoleKey.Y) + break; + } + _Log.Information(". . ."); + } + } + } + + public Shared.Models.Property GetProperty(Item item, List> filteredSourceDirectoryFileTuples, List parseExceptions) + { + Shared.Models.Property result; + if (item.ImageFileHolder is null) + throw new NullReferenceException(nameof(item.ImageFileHolder)); + bool firstPass = false; + bool isValidMetadataExtensions = _Configuration.ValidMetadataExtensions.Contains(item.ImageFileHolder.ExtensionLowered); + bool isIgnoreExtension = item.ValidImageFormatExtension && _Configuration.IgnoreExtensions.Contains(item.ImageFileHolder.ExtensionLowered); + result = GetPropertyOfPrivate(item, firstPass, filteredSourceDirectoryFileTuples, parseExceptions, isIgnoreExtension, isValidMetadataExtensions); + return result; + } + + public (long Ticks, string FilteredSourceDirectoryFile, string PropertyDirectory, int PropertyId)[] GetPropertyIds(List groupCollection, bool saveToCollection) + { + List<(long Ticks, string FilteredSourceDirectoryFile, string PropertyDirectory, int PropertyId)> results = new(); + int level; + string checkDirectory; + List directories; + string propertyDirectory; + Shared.Models.Property? property; + string angleBracket = AngleBracketCollection[0]; + foreach (DirectoryInfo group in groupCollection) + { + SetAngleBracketCollection(group.SourceDirectory); + if (string.IsNullOrEmpty(group.SourceDirectory)) + throw new Exception(); + if (!saveToCollection) + propertyDirectory = angleBracket.Replace("<>", "()"); + else + { + (level, directories) = Shared.Models.Stateless.Methods.IPath.Get(_Configuration.RootDirectory, group.SourceDirectory); + checkDirectory = Shared.Models.Stateless.Methods.IPath.GetDirectory(angleBracket, level, "[()]"); + propertyDirectory = Path.Combine(checkDirectory, string.Join(_Configuration.FileNameDirectorySeparator, directories)); + } + if (!Directory.Exists(propertyDirectory)) + _ = Directory.CreateDirectory(propertyDirectory); + for (int i = 0; i < group.SourceDirectoryFileHolderCollection.Length; i++) + { + property = group.PropertyCollection[i]; + if (property?.Id is null) + continue; + results.Add(new(property.GetDateTimes().Min().Ticks, group.FilteredSourceDirectoryFiles[i], propertyDirectory, property.Id.Value)); + } + } + return results.OrderBy(l => l.Ticks).ToArray(); + } + + public static List Get(Configuration configuration, A_Property propertyLogic) + { + List results; + long ticks = DateTime.Now.Ticks; + List exceptionsDirectories = new(); + results = Stateless.Container.GetContainers(configuration, propertyLogic); + propertyLogic.ParallelWork(ticks, results, firstPass: false); + if (exceptionsDirectories.Any()) + throw new Exception(); + return results; } } \ No newline at end of file diff --git a/Property/Models/Binder/Configuration.cs b/Property/Models/Binder/Configuration.cs index 020b4ad..c03bf92 100644 --- a/Property/Models/Binder/Configuration.cs +++ b/Property/Models/Binder/Configuration.cs @@ -1,3 +1,5 @@ +using Microsoft.Extensions.Configuration; +using Phares.Shared; using System.ComponentModel.DataAnnotations; using System.Text.Json; @@ -6,6 +8,8 @@ namespace View_by_Distance.Property.Models.Binder; public class Configuration { +#nullable disable + [Display(Name = "Date Group"), Required] public string DateGroup { get; set; } [Display(Name = "File Name Directory Separator"), Required] public string FileNameDirectorySeparator { get; set; } [Display(Name = "Force Property Last Write Time to Creation Time"), Required] public bool? ForcePropertyLastWriteTimeToCreationTime { get; set; } @@ -21,23 +25,7 @@ public class Configuration [Display(Name = "Verify to Season"), Required] public string[] VerifyToSeason { get; set; } [Display(Name = "Write Bitmap Data Bytes"), Required] public bool? WriteBitmapDataBytes { get; set; } - public Configuration() - { - DateGroup = string.Empty; - FileNameDirectorySeparator = string.Empty; - ForcePropertyLastWriteTimeToCreationTime = null; - IgnoreExtensions = Array.Empty(); - MaxImagesInDirectoryForTopLevelFirstPass = null; - Pattern = string.Empty; - PopulatePropertyId = null; - PropertiesChangedForProperty = null; - PropertyContentCollectionFiles = Array.Empty(); - RootDirectory = string.Empty; - ValidImageFormatExtensions = Array.Empty(); - ValidMetadataExtensions = Array.Empty(); - VerifyToSeason = Array.Empty(); - WriteBitmapDataBytes = null; - } +#nullable restore public override string ToString() { @@ -45,4 +33,61 @@ public class Configuration return result; } + private static Models.Configuration Get(Configuration configuration) + { + Models.Configuration result; + if (configuration.ForcePropertyLastWriteTimeToCreationTime is null) + throw new NullReferenceException(nameof(configuration.ForcePropertyLastWriteTimeToCreationTime)); + if (configuration.MaxImagesInDirectoryForTopLevelFirstPass is null) + throw new NullReferenceException(nameof(configuration.MaxImagesInDirectoryForTopLevelFirstPass)); + if (configuration.PopulatePropertyId is null) + throw new NullReferenceException(nameof(configuration.PopulatePropertyId)); + if (configuration.PropertiesChangedForProperty is null) + throw new NullReferenceException(nameof(configuration.PropertiesChangedForProperty)); + if (configuration.WriteBitmapDataBytes is null) + throw new NullReferenceException(nameof(configuration.WriteBitmapDataBytes)); + if (configuration.IgnoreExtensions is null) + configuration.IgnoreExtensions = Array.Empty(); + if (configuration.PropertyContentCollectionFiles is null) + configuration.PropertyContentCollectionFiles = Array.Empty(); + if (configuration.ValidImageFormatExtensions is null) + configuration.ValidImageFormatExtensions = Array.Empty(); + if (configuration.ValidMetadataExtensions is null) + configuration.ValidMetadataExtensions = Array.Empty(); + if (configuration.VerifyToSeason is null) + configuration.VerifyToSeason = Array.Empty(); + result = new(configuration.DateGroup, + configuration.FileNameDirectorySeparator, + configuration.ForcePropertyLastWriteTimeToCreationTime.Value, + configuration.IgnoreExtensions, + configuration.MaxImagesInDirectoryForTopLevelFirstPass.Value, + configuration.Pattern, + configuration.PopulatePropertyId.Value, + configuration.PropertiesChangedForProperty.Value, + configuration.PropertyContentCollectionFiles, + configuration.RootDirectory, + configuration.ValidImageFormatExtensions, + configuration.ValidMetadataExtensions, + configuration.VerifyToSeason, + configuration.WriteBitmapDataBytes.Value); + return result; + } + + public static Models.Configuration Get(IsEnvironment isEnvironment, IConfigurationRoot configurationRoot) + { + Models.Configuration result; + Configuration configuration; + if (isEnvironment is null) + configuration = configurationRoot.Get(); + else + { + string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); + string section = string.Concat(environmentName, ":", nameof(Configuration)); + IConfigurationSection configurationSection = configurationRoot.GetSection(section); + configuration = configurationSection.Get(); + } + result = Get(configuration); + return result; + } + } \ No newline at end of file diff --git a/Property/Models/Configuration.cs b/Property/Models/Configuration.cs index 44ff705..94f8f08 100644 --- a/Property/Models/Configuration.cs +++ b/Property/Models/Configuration.cs @@ -6,52 +6,40 @@ namespace View_by_Distance.Property.Models; public class Configuration { - protected readonly string _DateGroup; - protected readonly string _FileNameDirectorySeparator; - protected readonly bool? _ForcePropertyLastWriteTimeToCreationTime; - protected readonly string[] _IgnoreExtensions; - protected readonly int? _MaxImagesInDirectoryForTopLevelFirstPass; - protected readonly string _Pattern; - protected readonly bool? _PopulatePropertyId; - protected readonly bool? _PropertiesChangedForProperty; - protected readonly string[] _PropertyContentCollectionFiles; protected string _RootDirectory; - protected readonly string[] _ValidImageFormatExtensions; - protected readonly string[] _ValidMetadataExtensions; - protected readonly string[] _VerifyToSeason; - protected readonly bool? _WriteBitmapDataBytes; - public string DateGroup => _DateGroup; - public string FileNameDirectorySeparator => _FileNameDirectorySeparator; - public bool? ForcePropertyLastWriteTimeToCreationTime => _ForcePropertyLastWriteTimeToCreationTime; - public string[] IgnoreExtensions => _IgnoreExtensions; - public int? MaxImagesInDirectoryForTopLevelFirstPass => _MaxImagesInDirectoryForTopLevelFirstPass; - public string Pattern => _Pattern; - public bool? PopulatePropertyId => _PopulatePropertyId; - public bool? PropertiesChangedForProperty => _PropertiesChangedForProperty; - public string[] PropertyContentCollectionFiles => _PropertyContentCollectionFiles; public string RootDirectory => _RootDirectory; - public string[] ValidImageFormatExtensions => _ValidImageFormatExtensions; - public string[] ValidMetadataExtensions => _ValidMetadataExtensions; - public string[] VerifyToSeason => _VerifyToSeason; - public bool? WriteBitmapDataBytes => _WriteBitmapDataBytes; + + public string DateGroup { init; get; } + public string FileNameDirectorySeparator { init; get; } + public bool ForcePropertyLastWriteTimeToCreationTime { init; get; } + public string[] IgnoreExtensions { init; get; } + public int MaxImagesInDirectoryForTopLevelFirstPass { init; get; } + public string Pattern { init; get; } + public bool PopulatePropertyId { init; get; } + public bool PropertiesChangedForProperty { init; get; } + public string[] PropertyContentCollectionFiles { init; get; } + public string[] ValidImageFormatExtensions { init; get; } + public string[] ValidMetadataExtensions { init; get; } + public string[] VerifyToSeason { init; get; } + public bool WriteBitmapDataBytes { init; get; } [JsonConstructor] - public Configuration(string dateGroup, string fileNameDirectorySeparator, bool? forcePropertyLastWriteTimeToCreationTime, string[] ignoreExtensions, int? maxImagesInDirectoryForTopLevelFirstPass, string pattern, bool? populatePropertyId, bool? propertiesChangedForProperty, string[] propertyContentCollectionFiles, string rootDirectory, string[] validImageFormatExtensions, string[] validMetadataExtensions, string[] verifyToSeason, bool? writeBitmapDataBytes) + public Configuration(string dateGroup, string fileNameDirectorySeparator, bool forcePropertyLastWriteTimeToCreationTime, string[] ignoreExtensions, int maxImagesInDirectoryForTopLevelFirstPass, string pattern, bool populatePropertyId, bool propertiesChangedForProperty, string[] propertyContentCollectionFiles, string rootDirectory, string[] validImageFormatExtensions, string[] validMetadataExtensions, string[] verifyToSeason, bool writeBitmapDataBytes) { - _DateGroup = dateGroup; - _FileNameDirectorySeparator = fileNameDirectorySeparator; - _ForcePropertyLastWriteTimeToCreationTime = forcePropertyLastWriteTimeToCreationTime; - _IgnoreExtensions = ignoreExtensions; - _MaxImagesInDirectoryForTopLevelFirstPass = maxImagesInDirectoryForTopLevelFirstPass; - _Pattern = pattern; - _PopulatePropertyId = populatePropertyId; - _PropertiesChangedForProperty = propertiesChangedForProperty; - _PropertyContentCollectionFiles = propertyContentCollectionFiles; + DateGroup = dateGroup; + FileNameDirectorySeparator = fileNameDirectorySeparator; + ForcePropertyLastWriteTimeToCreationTime = forcePropertyLastWriteTimeToCreationTime; + IgnoreExtensions = ignoreExtensions; + MaxImagesInDirectoryForTopLevelFirstPass = maxImagesInDirectoryForTopLevelFirstPass; + Pattern = pattern; + PopulatePropertyId = populatePropertyId; + PropertiesChangedForProperty = propertiesChangedForProperty; + PropertyContentCollectionFiles = propertyContentCollectionFiles; _RootDirectory = rootDirectory; - _ValidImageFormatExtensions = validImageFormatExtensions; - _ValidMetadataExtensions = validMetadataExtensions; - _VerifyToSeason = verifyToSeason; - _WriteBitmapDataBytes = writeBitmapDataBytes; + ValidImageFormatExtensions = validImageFormatExtensions; + ValidMetadataExtensions = validMetadataExtensions; + VerifyToSeason = verifyToSeason; + WriteBitmapDataBytes = writeBitmapDataBytes; } public override string ToString() @@ -62,18 +50,14 @@ public class Configuration public void Update() => _RootDirectory = Path.GetFullPath(_RootDirectory); - public static void Verify(Configuration? propertyConfiguration) + public void ChangeRootDirectory(string rootDirectory) => _RootDirectory = rootDirectory; + + public static void Verify(Configuration propertyConfiguration) { if (propertyConfiguration is null) throw new NullReferenceException(nameof(propertyConfiguration)); - if (propertyConfiguration.ForcePropertyLastWriteTimeToCreationTime is null) - throw new NullReferenceException(nameof(propertyConfiguration.ForcePropertyLastWriteTimeToCreationTime)); if (propertyConfiguration.IgnoreExtensions is null || !propertyConfiguration.IgnoreExtensions.Any()) throw new NullReferenceException(nameof(propertyConfiguration.IgnoreExtensions)); - if (propertyConfiguration.PopulatePropertyId is null) - throw new NullReferenceException(nameof(propertyConfiguration.PopulatePropertyId)); - if (propertyConfiguration.PropertiesChangedForProperty is null) - throw new NullReferenceException(nameof(propertyConfiguration.PropertiesChangedForProperty)); if (propertyConfiguration.PropertyContentCollectionFiles is null) throw new NullReferenceException(nameof(propertyConfiguration.PropertyContentCollectionFiles)); if (propertyConfiguration.ValidImageFormatExtensions is null || !propertyConfiguration.ValidImageFormatExtensions.Any()) @@ -82,8 +66,6 @@ public class Configuration throw new NullReferenceException(nameof(propertyConfiguration.ValidMetadataExtensions)); if (propertyConfiguration.VerifyToSeason is null || !propertyConfiguration.VerifyToSeason.Any()) throw new NullReferenceException(nameof(propertyConfiguration.VerifyToSeason)); - if (propertyConfiguration.WriteBitmapDataBytes is null) - throw new NullReferenceException(nameof(propertyConfiguration.WriteBitmapDataBytes)); if (Path.GetPathRoot(propertyConfiguration.RootDirectory) == propertyConfiguration.RootDirectory) throw new NullReferenceException(nameof(propertyConfiguration.RootDirectory)); if (propertyConfiguration is null) @@ -98,6 +80,4 @@ public class Configuration throw new NullReferenceException(nameof(propertyConfiguration.RootDirectory)); } - public void ChangeRootDirectory(string rootDirectory) => _RootDirectory = rootDirectory; - } \ No newline at end of file diff --git a/Property/Models/DirectoryInfo.cs b/Property/Models/DirectoryInfo.cs index 1e35e35..5a1d7b5 100644 --- a/Property/Models/DirectoryInfo.cs +++ b/Property/Models/DirectoryInfo.cs @@ -3,24 +3,24 @@ namespace View_by_Distance.Property.Models; public class DirectoryInfo { - protected readonly FileHolder[] _SourceDirectoryFileHolderCollection; + protected readonly Shared.Models.FileHolder[] _SourceDirectoryFileHolderCollection; protected readonly string[] _FilteredSourceDirectoryFiles; protected readonly int _G; protected readonly bool[] _Moved; protected readonly bool?[] _Changed; - protected readonly A_Property?[] _PropertyCollection; + protected readonly Shared.Models.Property?[] _PropertyCollection; protected readonly FileInfo?[] _PropertyFileHolderCollection; protected readonly int _R; protected readonly string _SourceDirectory; protected readonly bool[] _ValidImageFormatExtensionCollection; protected readonly bool[] _WrongYear; - public FileHolder[] SourceDirectoryFileHolderCollection => _SourceDirectoryFileHolderCollection; + public Shared.Models.FileHolder[] SourceDirectoryFileHolderCollection => _SourceDirectoryFileHolderCollection; [Obsolete($"Use {nameof(SourceDirectoryFileHolderCollection)}")] public string[] FilteredSourceDirectoryFiles => _FilteredSourceDirectoryFiles; public int G => _G; public bool[] Moved => _Moved; public bool?[] Changed => _Changed; - public A_Property?[] PropertyCollection => _PropertyCollection; + public Shared.Models.Property?[] PropertyCollection => _PropertyCollection; public FileInfo?[] PropertyFileHolderCollection => _PropertyFileHolderCollection; public int R => _R; public string SourceDirectory => _SourceDirectory; @@ -37,10 +37,11 @@ public class DirectoryInfo _Moved = Enumerable.Repeat(false, length).ToArray(); _WrongYear = Enumerable.Repeat(false, length).ToArray(); _FilteredSourceDirectoryFiles = filteredSourceDirectoryFiles; - _PropertyCollection = Enumerable.Repeat(null, length).ToArray(); _ValidImageFormatExtensionCollection = Enumerable.Repeat(false, length).ToArray(); _PropertyFileHolderCollection = Enumerable.Repeat(null, length).ToArray(); - _SourceDirectoryFileHolderCollection = (from l in filteredSourceDirectoryFiles select new FileHolder(l)).ToArray(); + _PropertyCollection = Enumerable.Repeat(null, length).ToArray(); + _SourceDirectoryFileHolderCollection = (from l in filteredSourceDirectoryFiles select new Shared.Models.FileHolder(l)).ToArray(); + } } \ No newline at end of file diff --git a/Property/Models/Item.cs b/Property/Models/Item.cs deleted file mode 100644 index 6892bcd..0000000 --- a/Property/Models/Item.cs +++ /dev/null @@ -1,318 +0,0 @@ -using System.Text.Json.Serialization; -using View_by_Distance.Shared.Models; -using View_by_Distance.Shared.Models.Properties; - -namespace View_by_Distance.Property.Models; - -public class Item -{ - - protected readonly bool? _Abandoned; - protected readonly bool? _Changed; - protected List _Closest; - protected List _Faces; - protected readonly FileHolder? _ImageFileHolder; - protected bool? _Moved; - protected List _Named; - protected readonly bool? _NoJson; - protected A_Property? _Property; - protected readonly string _RelativePath; - protected FileHolder? _ResizedFileHolder; - protected readonly string _SourceDirectoryFile; - protected bool _ValidImageFormatExtension; - public bool? Abandoned => _Abandoned; - public bool? Changed => _Changed; - public List Closest => _Closest; - public List Faces => _Faces; - public FileHolder? ImageFileHolder => _ImageFileHolder; - public bool? Moved => _Moved; - public bool? NoJson => _NoJson; - public List Named => _Named; - public A_Property? Property => _Property; - public string RelativePath => _RelativePath; - public FileHolder? ResizedFileHolder => _ResizedFileHolder; - public string SourceDirectoryFile => _SourceDirectoryFile; - public bool ValidImageFormatExtension => _ValidImageFormatExtension; - - [JsonConstructor] - public Item(bool? abandoned, bool? changed, List closest, List faces, FileHolder? imageFileHolder, bool? moved, List named, bool? noJson, A_Property? property, string relativePath, FileHolder? resizedFileHolder, string sourceDirectoryFile, bool validImageFormatExtension) - { - _Abandoned = abandoned; - _Changed = changed; - _Closest = closest; - _Faces = faces; - _ImageFileHolder = imageFileHolder; - _Moved = moved; - _Named = named; - _NoJson = noJson; - _Property = property; - _RelativePath = relativePath; - _ResizedFileHolder = resizedFileHolder; - _SourceDirectoryFile = sourceDirectoryFile; - _ValidImageFormatExtension = validImageFormatExtension; - } - - public Item(string sourceDirectoryFile, string relativePath, FileHolder? imageFileInfo, bool isValidImageFormatExtension, A_Property? property, bool? abandoned, bool? changed) - { - _Faces = new(); - _Named = new(); - _Closest = new(); - _Changed = changed; - _Property = property; - _Abandoned = abandoned; - _NoJson = abandoned is null; - _RelativePath = relativePath; - _ImageFileHolder = imageFileInfo; - _SourceDirectoryFile = sourceDirectoryFile; - _ValidImageFormatExtension = isValidImageFormatExtension; - if (relativePath.EndsWith(".json")) - throw new ArgumentException("Can not be a *.json file!"); - if (imageFileInfo is not null && imageFileInfo.ExtensionLowered is ".json") - throw new ArgumentException("Can not be a *.json file!"); - } - - internal void SetMoved(bool moved) => _Moved = moved; - - public static string GetWrongYearFlag(bool? isWrongYear) => isWrongYear is null ? "#" : isWrongYear.Value ? "~" : "="; - - public void SetResizedFileHolder(FileHolder fileHolder) => _ResizedFileHolder = fileHolder; - - public bool Any() => (_Abandoned.HasValue && _Abandoned.Value) || (_Changed.HasValue && _Changed.Value) || (_Moved.HasValue && _Moved.Value) || (_NoJson.HasValue && _NoJson.Value); - - public void Update(A_Property property) => _Property = property; - - public (bool?, string[]) IsWrongYear() - { - (bool?, string[]) result; - if (_Property is null || _ImageFileHolder is null) - throw new NullReferenceException(); - DateTime? minimumDateTime = Stateless.A_Property.GetMinimumDateTime(_Property); - result = _Property.IsWrongYear(_ImageFileHolder.FullName, minimumDateTime); - return result; - } - - public static void AddToNamed(PropertyLogic propertyLogic, List items) - { - bool? isWrongYear; - DateTime minimumDateTime; - PersonBirthday? personBirthday; - double deterministicHashCodeKey; - List personKeys = new(); - foreach (Item item in items) - { - if (item.ImageFileHolder is null) - continue; - if (item.Property?.Id is null || item.ResizedFileHolder is null) - continue; - foreach (IFace face in item.Faces) - { - personKeys.Clear(); - if (face.LocationIndex is null) - continue; - deterministicHashCodeKey = Models.Named.GetDeterministicHashCodeKey(item, face); - if (!propertyLogic.NamedDeterministicHashCodeKeyValuePairs.ContainsKey(deterministicHashCodeKey)) - continue; - minimumDateTime = Stateless.A_Property.GetMinimumDateTime(item.Property); - personKeys.AddRange(propertyLogic.NamedDeterministicHashCodeKeyValuePairs[deterministicHashCodeKey]); - (isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime); - for (int i = 0; i < personKeys.Count; i++) - { - personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKeys[i]); - if (personBirthday is null) - continue; - item.Named.Add(new(isWrongYear, minimumDateTime, face.Location.NormalizedPixelPercentage, personBirthday)); - } - } - if (!personKeys.Any()) - { - if (!propertyLogic.NamedFaceInfoDeterministicHashCodeKeyValuePairs.ContainsKey(item.Property.Id.Value)) - continue; - minimumDateTime = Stateless.A_Property.GetMinimumDateTime(item.Property); - personKeys.AddRange(propertyLogic.NamedFaceInfoDeterministicHashCodeKeyValuePairs[item.Property.Id.Value]); - (isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime); - for (int i = 0; i < personKeys.Count; i++) - { - personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKeys[i]); - if (personBirthday is null) - continue; - item.Named.Add(new(isWrongYear, minimumDateTime, personBirthday)); - } - } - } - } - - public static List<(Item, (string, IFace?, (string, string, string, string))[])> GetCollection(PropertyLogic propertyLogic, List items, string dFacesContentDirectory) - { - List<(Item, (string, IFace?, (string, string, string, string))[])> results = new(); - Item item; - string[] keys; - string directory; - string personKey; - bool? isWrongYear; - const int zero = 0; - TimeSpan? timeSpan; - string copyFileName; - string copyDirectory; - string? relativePath; - string isWrongYearFlag; - string shortcutFileName; - string subDirectoryName; - List indices = new(); - DateTime? minimumDateTime; - List faceCollection; - PersonBirthday? personBirthday; - List<(string, IFace?, (string, string, string, string))> collection; - for (int i = 0; i < items.Count; i++) - { - indices.Clear(); - copyFileName = string.Empty; - copyDirectory = string.Empty; - item = items[i]; - if (item.ImageFileHolder is null) - continue; - relativePath = Path.GetDirectoryName($"C:{item.RelativePath}"); - if (string.IsNullOrEmpty(relativePath) || relativePath.Length < 3) - continue; - if (item.Property?.Id is null || item.ResizedFileHolder is null) - continue; - collection = new(); - if (!propertyLogic.NamedFaceInfoDeterministicHashCodeKeyValuePairs.ContainsKey(item.Property.Id.Value)) - { - faceCollection = new(); - personKey = string.Empty; - directory = Path.Combine(dFacesContentDirectory, $"Unnamed{relativePath[2..]}"); - } - else - { - faceCollection = item.Faces; - keys = propertyLogic.NamedFaceInfoDeterministicHashCodeKeyValuePairs[item.Property.Id.Value]; - minimumDateTime = Stateless.A_Property.GetMinimumDateTime(item.Property); - if (minimumDateTime is null) - continue; - (isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime.Value); - isWrongYearFlag = GetWrongYearFlag(isWrongYear); - subDirectoryName = $"{isWrongYearFlag}{minimumDateTime.Value:yyyy}"; - if (!faceCollection.Any()) - { - personKey = string.Empty; - directory = Path.Combine(dFacesContentDirectory, $"None{relativePath[2..]}", subDirectoryName); - } - else if (keys.Length != 1) - { - personKey = string.Empty; - directory = Path.Combine(dFacesContentDirectory, $"Not Supported{relativePath[2..]}", subDirectoryName); - } - else if (faceCollection.Count != 1) - { - personKey = string.Empty; - directory = Path.Combine(dFacesContentDirectory, $"Many{relativePath[2..]}", subDirectoryName); - } - else - { - indices.Add(zero); - personKey = keys[zero]; - personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKey); - if (personBirthday is null) - continue; - timeSpan = Shared.Models.Stateless.Methods.IPersonBirthday.GetTimeSpan(minimumDateTime.Value, isWrongYear, personBirthday); - if (timeSpan.HasValue) - { - if (timeSpan.Value.Ticks < 0) - subDirectoryName = "!---"; - else - subDirectoryName = $"^{Math.Floor(timeSpan.Value.TotalDays / 365):000}"; - } - directory = Path.Combine(dFacesContentDirectory, "Shortcuts", personKey, subDirectoryName); - if (faceCollection[zero].Populated) - copyDirectory = Path.Combine(dFacesContentDirectory, "Images", personKey, subDirectoryName); - else - copyDirectory = Path.Combine(dFacesContentDirectory, "ImagesBut", personKey, subDirectoryName); - copyFileName = Path.Combine(copyDirectory, $"{item.Property.Id.Value}{item.ResizedFileHolder.ExtensionLowered}"); - } - } - shortcutFileName = Path.Combine(directory, $"{item.Property.Id.Value}.lnk"); - if (string.IsNullOrEmpty(personKey) || !indices.Any()) - collection.Add(new(personKey, null, (directory, copyDirectory, copyFileName, shortcutFileName))); - else - { - foreach (int index in indices) - collection.Add(new(personKey, faceCollection[index], (directory, copyDirectory, copyFileName, shortcutFileName))); - } - results.Add(new(item, collection.ToArray())); - } - return results; - } - - public static string GetKey(DateTime minimumDateTime, bool? isWrongYear, PersonBirthday personBirthday) - { - string result; - string personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthday); - TimeSpan? timeSpan = Shared.Models.Stateless.Methods.IPersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday); - if (timeSpan.HasValue && timeSpan.Value.Ticks < 0) - result = string.Concat(personKey, "!---"); - else if (timeSpan.HasValue) - result = string.Concat(personKey, $"^{Math.Floor(timeSpan.Value.TotalDays / 365):000}"); - else - { - string isWrongYearFlag = GetWrongYearFlag(isWrongYear); - result = string.Concat(personKey, $"{isWrongYearFlag}{minimumDateTime:yyyy}"); - } - return result; - } - - public static string GetDirectory(string directory, string subDirectory, DateTime minimumDateTime, bool? isWrongYear, PersonBirthday personBirthday, string personKey) - { - string result; - TimeSpan? timeSpan = Shared.Models.Stateless.Methods.IPersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday); - if (timeSpan.HasValue && timeSpan.Value.Ticks < 0) - result = Path.Combine(directory, subDirectory, personKey, "!---"); - else if (timeSpan.HasValue) - result = Path.Combine(directory, subDirectory, personKey, $"^{Math.Floor(timeSpan.Value.TotalDays / 365):000}"); - else - { - string isWrongYearFlag = GetWrongYearFlag(isWrongYear); - result = Path.Combine(directory, subDirectory, personKey, $"{isWrongYearFlag}{minimumDateTime:yyyy}"); - } - return result; - } - - public static Dictionary> GetKeyValuePairs(string argZero, List containers) - { - Dictionary> results = new(); - string key; - foreach (Container container in containers) - { - if (!container.Items.Any()) - continue; - if (!container.SourceDirectory.StartsWith(argZero)) - continue; - foreach (Item item in container.Items) - { - if (item.ImageFileHolder is null || item.Property is null || !item.Named.Any()) - continue; - foreach (Named named in item.Named) - { - if (named.NormalizedPixelPercentage is null && (item.Named.Count != 1 || item.Faces.Count != 1)) - continue; - foreach (IFace face in item.Faces) - { - if (!face.Populated) - continue; - if (named.PersonBirthday is null) - continue; - if (named.NormalizedPixelPercentage.HasValue && named.NormalizedPixelPercentage.Value != face.Location?.NormalizedPixelPercentage) - continue; - key = GetKey(named.MinimumDateTime, named.IsWrongYear, named.PersonBirthday); - if (!results.ContainsKey(key)) - results.Add(key, new()); - results[key].Add(new(named.MinimumDateTime, named.IsWrongYear, named.PersonBirthday, face)); - if (named.NormalizedPixelPercentage is null) - break; - } - } - } - } - return results; - } - -} \ No newline at end of file diff --git a/Property/Models/Named.cs b/Property/Models/Named.cs deleted file mode 100644 index 9701310..0000000 --- a/Property/Models/Named.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System.Text.Json.Serialization; -using View_by_Distance.Shared.Models; -using View_by_Distance.Shared.Models.Properties; - -namespace View_by_Distance.Property.Models; - -public class Named -{ - - protected readonly bool? _IsWrongYear; - protected readonly DateTime _MinimumDateTime; - protected readonly int? _NormalizedPixelPercentage; - protected readonly PersonBirthday? _PersonBirthday; - public bool? IsWrongYear => _IsWrongYear; - public DateTime MinimumDateTime => _MinimumDateTime; - public int? NormalizedPixelPercentage => _NormalizedPixelPercentage; - public PersonBirthday? PersonBirthday => _PersonBirthday; - - [JsonConstructor] - public Named(bool? isWrongYear, DateTime minimumDateTime, int? normalizedPixelPercentage, PersonBirthday? personBirthday) - { - _IsWrongYear = isWrongYear; - _MinimumDateTime = minimumDateTime; - _NormalizedPixelPercentage = normalizedPixelPercentage; - _PersonBirthday = personBirthday; - } - - public Named(bool? isWrongYear, DateTime minimumDateTime, PersonBirthday? personBirthday) : - this(isWrongYear, minimumDateTime, null, personBirthday) - { } - - private static double GetDeterministicHashCodeFileName(int id, int normalizedPixelPercentage) - => double.Parse($"{id}.{normalizedPixelPercentage}"); - - public static double GetDeterministicHashCodeKey(Item item, Closest closest) - { - double result; - if (item.Property?.Id is null || item.ImageFileHolder is null || closest.NormalizedPixelPercentage is null) - throw new NullReferenceException(); - result = GetDeterministicHashCodeFileName(item.Property.Id.Value, closest.NormalizedPixelPercentage.Value); - return result; - } - - public static double GetDeterministicHashCodeKey(Item item, IFace face) - { - double result; - if (item.Property?.Id is null || item.ImageFileHolder is null || face.Location?.NormalizedPixelPercentage is null) - throw new NullReferenceException(); - result = GetDeterministicHashCodeFileName(item.Property.Id.Value, face.Location.NormalizedPixelPercentage.Value); - return result; - } - - public static double? GetReversedDeterministicHashCode(string fileName) - { - double? result; - if (fileName.Length < 2 || fileName[1..].Contains('-')) - result = null; - else - { - string[] segments = fileName.Split('.'); - if (segments.Length < 2) - throw new Exception(); - string id = segments[0]; - string normalizedPixelPercentage = segments[1]; - if (!double.TryParse(string.Concat(id, '.', normalizedPixelPercentage), out double resultValue)) - result = null; - else - result = resultValue; - } - return result; - } - - public static (string?, double?) GetReversedDeterministicHashCode(Dictionary> keyValuePairs, string file) - { - double? result; - string? check; - string fileName = Path.GetFileName(file); - if (!fileName.Contains('-')) - { - check = null; - result = null; - } - else - { - string id; - int? normalizedPixelPercentage; - if (!keyValuePairs.Any()) - { - check = null; - id = string.Empty; - normalizedPixelPercentage = null; - } - else - { - string[] segments = fileName.Split(' '); - if (segments.Length < 3) - throw new Exception(); - id = segments[2].Split('.')[0]; - string locationIdex = segments[0]; - if (!int.TryParse(id, out int idValue) || !int.TryParse(locationIdex, out int locationIndexValue) || !keyValuePairs.ContainsKey(idValue)) - { - check = null; - id = string.Empty; - normalizedPixelPercentage = null; - } - else - { - List faces = keyValuePairs[idValue]; - if (faces.Count <= locationIndexValue) - { - check = null; - id = string.Empty; - normalizedPixelPercentage = null; - } - else - { - IFace face = faces[locationIndexValue]; - if (face.Location?.NormalizedPixelPercentage is null) - { - check = null; - id = string.Empty; - normalizedPixelPercentage = null; - } - else - { - string extensionLowered = Path.GetExtension(file).ToLower(); - normalizedPixelPercentage = face.Location.NormalizedPixelPercentage.Value; - double deterministicHashCodeKey = GetDeterministicHashCodeFileName(idValue, normalizedPixelPercentage.Value); - check = Path.Combine(string.Concat(Path.GetDirectoryName(file)), $"{deterministicHashCodeKey}{extensionLowered}"); - } - } - } - } - if (normalizedPixelPercentage is null || !double.TryParse(string.Concat(id, '.', normalizedPixelPercentage.Value), out double resultValue)) - result = null; - else - result = resultValue; - } - return new(check, result); - } - -} \ No newline at end of file diff --git a/Property/Models/PropertyLogic.cs b/Property/Models/PropertyLogic.cs deleted file mode 100644 index 0c85166..0000000 --- a/Property/Models/PropertyLogic.cs +++ /dev/null @@ -1,972 +0,0 @@ -using ShellProgressBar; -using System.Diagnostics; -using System.Drawing; -using System.Drawing.Imaging; -using System.Globalization; -using System.Runtime.InteropServices; -using System.Text; -using System.Text.Json; -using View_by_Distance.Property.Models.Stateless; -using View_by_Distance.Shared.Models.Properties; -using View_by_Distance.Shared.Models.Stateless; - -namespace View_by_Distance.Property.Models; - -public class PropertyLogic -{ - - protected readonly List<(int, string[])> _AllCollection; - protected readonly List _ExceptionsDirectories; - protected readonly Dictionary _KeyValuePairs; - protected readonly Dictionary _IndicesFromNew; - protected readonly string _DeterministicHashCodeRootDirectory; - protected readonly Dictionary _SixCharacterNamedFaceInfo; - protected readonly Dictionary _NamedFaceInfoDeterministicHashCodeKeyValuePairs; - protected readonly Dictionary _NamedDeterministicHashCodeKeyValuePairs; - protected readonly Dictionary _IncorrectDeterministicHashCodeKeyValuePairs; - - public bool Reverse { get; } - public List AngleBracketCollection { get; } - public Dictionary KeyValuePairs => _KeyValuePairs; - public Dictionary IndicesFromNew => _IndicesFromNew; - public List ExceptionsDirectories => _ExceptionsDirectories; - public string DeterministicHashCodeRootDirectory => _DeterministicHashCodeRootDirectory; - public Dictionary NamedDeterministicHashCodeKeyValuePairs => _NamedDeterministicHashCodeKeyValuePairs; - public Dictionary IncorrectDeterministicHashCodeKeyValuePairs => _IncorrectDeterministicHashCodeKeyValuePairs; - public Dictionary NamedFaceInfoDeterministicHashCodeKeyValuePairs => _NamedFaceInfoDeterministicHashCodeKeyValuePairs; - - private readonly Model? _Model; - private readonly Serilog.ILogger? _Log; - private readonly string[] _VerifyToSeason; - private readonly int _MaxDegreeOfParallelism; - private readonly ASCIIEncoding _ASCIIEncoding; - private readonly Configuration _Configuration; - private readonly PredictorModel? _PredictorModel; - private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; - - public PropertyLogic(int maxDegreeOfParallelism, Configuration configuration, bool reverse, Model? model, PredictorModel? predictorModel) - { - _Model = model; - Reverse = reverse; - _AllCollection = new(); - _Configuration = configuration; - _ExceptionsDirectories = new(); - _PredictorModel = predictorModel; - _ASCIIEncoding = new ASCIIEncoding(); - AngleBracketCollection = new List(); - _Log = Serilog.Log.ForContext(); - _MaxDegreeOfParallelism = maxDegreeOfParallelism; - Dictionary? namedFaceInfoDeterministicHashCode; - _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; - if (configuration.VerifyToSeason is null || !configuration.VerifyToSeason.Any()) - throw new Exception(); - _VerifyToSeason = configuration.VerifyToSeason.Select(l => Path.Combine(configuration.RootDirectory, l)).ToArray(); - string json; - string[] files; - string fullPath; - Dictionary? keyValuePairs; - string deterministicHashCodeRootDirectory; - List>? collection; - Dictionary indicesFromNew = new(); - Dictionary? sixCharacterNamedFaceInfo; - Dictionary namedDeterministicHashCode = new(); - Dictionary incorrectDeterministicHashCode = new(); - string? rootDirectoryParent = Path.GetDirectoryName(configuration.RootDirectory); - if (string.IsNullOrEmpty(rootDirectoryParent)) - throw new NullReferenceException(nameof(rootDirectoryParent)); - files = Directory.GetFiles(rootDirectoryParent, "*DeterministicHashCode*.json", SearchOption.TopDirectoryOnly); - if (files.Length != 1) - namedFaceInfoDeterministicHashCode = new(); - else - { - json = File.ReadAllText(files[0]); - namedFaceInfoDeterministicHashCode = JsonSerializer.Deserialize>(json); - if (namedFaceInfoDeterministicHashCode is null) - throw new NullReferenceException(nameof(namedFaceInfoDeterministicHashCode)); - } - string[] directories = Directory.GetDirectories(rootDirectoryParent, "*DeterministicHashCode*", SearchOption.TopDirectoryOnly); - if (!directories.Any()) - deterministicHashCodeRootDirectory = string.Empty; - else - { - Dictionary> faces = new(); - deterministicHashCodeRootDirectory = directories[0]; - SetKeyValuePairs(deterministicHashCodeRootDirectory, namedDeterministicHashCode, incorrectDeterministicHashCode, faces); - } - if (!namedFaceInfoDeterministicHashCode.Any()) - sixCharacterNamedFaceInfo = new(); - else - { - files = Directory.GetFiles(rootDirectoryParent, "*SixCharacter*.json", SearchOption.TopDirectoryOnly); - if (files.Length != 1) - sixCharacterNamedFaceInfo = new(); - else - { - json = File.ReadAllText(files[0]); - sixCharacterNamedFaceInfo = JsonSerializer.Deserialize>(json); - if (sixCharacterNamedFaceInfo is null) - throw new NullReferenceException(nameof(sixCharacterNamedFaceInfo)); - } - } - files = Directory.GetFiles(rootDirectoryParent, "*keyValuePairs*.json", SearchOption.TopDirectoryOnly); - if (files.Length != 1) - keyValuePairs = new(); - else - { - json = File.ReadAllText(files[0]); - keyValuePairs = JsonSerializer.Deserialize>(json); - if (keyValuePairs is null) - throw new NullReferenceException(nameof(keyValuePairs)); - } - foreach (string propertyContentCollectionFile in configuration.PropertyContentCollectionFiles) - { - fullPath = Path.GetFullPath(string.Concat(rootDirectoryParent, propertyContentCollectionFile)); - if (fullPath.Contains(configuration.RootDirectory)) - continue; - if (!File.Exists(fullPath)) - continue; - json = File.ReadAllText(fullPath); - collection = JsonSerializer.Deserialize>>(json); - if (collection is null) - throw new NullReferenceException(nameof(collection)); - foreach (KeyValuePair keyValuePair in collection) - { - if (indicesFromNew.ContainsKey(keyValuePair.Key)) - continue; - indicesFromNew.Add(keyValuePair.Key, keyValuePair.Value); - } - } - _KeyValuePairs = keyValuePairs; - _IndicesFromNew = indicesFromNew; - _SixCharacterNamedFaceInfo = sixCharacterNamedFaceInfo; - _NamedDeterministicHashCodeKeyValuePairs = namedDeterministicHashCode; - _DeterministicHashCodeRootDirectory = deterministicHashCodeRootDirectory; - _IncorrectDeterministicHashCodeKeyValuePairs = incorrectDeterministicHashCode; - _NamedFaceInfoDeterministicHashCodeKeyValuePairs = namedFaceInfoDeterministicHashCode; - } - - private static void SetKeyValuePairs(string deterministicHashCodeRootDirectory, List<(string, double)> named, List<(string, double)> incorrect, Dictionary> keyValuePairs) - { - string[] files; - string fileName; - string personKey; - string? checkFile; - string[] yearDirectories; - string[] personKeyDirectories; - string[] personNameDirectories; - double? idAndNormalizedPixelPercentage; - string[] ticksDirectories = Directory.GetDirectories(deterministicHashCodeRootDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string ticksDirectory in ticksDirectories) - { - if (!ticksDirectory.EndsWith(')')) - continue; - personKeyDirectories = Directory.GetDirectories(ticksDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string personKeyDirectory in personKeyDirectories) - { - personKey = Path.GetFileName(personKeyDirectory); - yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string yearDirectory in yearDirectories) - { - files = Directory.GetFiles(yearDirectory, "*", SearchOption.TopDirectoryOnly); - personNameDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string file in files) - { - if (file.EndsWith(".lnk")) - continue; - fileName = Path.GetFileName(file); - idAndNormalizedPixelPercentage = Named.GetReversedDeterministicHashCode(fileName); - if (idAndNormalizedPixelPercentage is null) - { - (checkFile, idAndNormalizedPixelPercentage) = Named.GetReversedDeterministicHashCode(keyValuePairs, file); - if (idAndNormalizedPixelPercentage is null) - break; - if (!string.IsNullOrEmpty(checkFile)) - File.Move(file, checkFile); - } - incorrect.Add(new(personKey, idAndNormalizedPixelPercentage.Value)); - } - foreach (string personNameDirectory in personNameDirectories) - { - files = Directory.GetFiles(personNameDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string file in files) - { - if (file.EndsWith(".lnk")) - continue; - fileName = Path.GetFileName(file); - idAndNormalizedPixelPercentage = Named.GetReversedDeterministicHashCode(fileName); - if (idAndNormalizedPixelPercentage is null) - { - (checkFile, idAndNormalizedPixelPercentage) = Named.GetReversedDeterministicHashCode(keyValuePairs, file); - if (idAndNormalizedPixelPercentage is null) - break; - if (!string.IsNullOrEmpty(checkFile)) - File.Move(file, checkFile); - } - named.Add(new(personKey, idAndNormalizedPixelPercentage.Value)); - } - } - } - } - } - } - - private static void SetKeyValuePairs(string deterministicHashCodeRootDirectory, Dictionary namedDeterministicHashCode, Dictionary incorrectDeterministicHashCode, Dictionary> keyValuePairs) - { - Dictionary> namedKeyValuePairs = new(); - Dictionary> incorrectKeyValuePairs = new(); - List<(string PersonKey, double IdAndNormalizedPixelPercentage)> named = new(); - List<(string PersonKey, double IdAndNormalizedPixelPercentage)> incorrect = new(); - SetKeyValuePairs(deterministicHashCodeRootDirectory, named, incorrect, keyValuePairs); - named = (from l in named orderby l.IdAndNormalizedPixelPercentage select l).ToList(); - incorrect = (from l in incorrect orderby l.IdAndNormalizedPixelPercentage select l).ToList(); - foreach ((string personKey, double idAndNormalizedPixelPercentage) in named) - { - if (!namedKeyValuePairs.ContainsKey(idAndNormalizedPixelPercentage)) - namedKeyValuePairs.Add(idAndNormalizedPixelPercentage, new()); - namedKeyValuePairs[idAndNormalizedPixelPercentage].Add(personKey); - } - foreach ((string personKey, double idAndNormalizedPixelPercentage) in incorrect) - { - if (!incorrectKeyValuePairs.ContainsKey(idAndNormalizedPixelPercentage)) - incorrectKeyValuePairs.Add(idAndNormalizedPixelPercentage, new()); - incorrectKeyValuePairs[idAndNormalizedPixelPercentage].Add(personKey); - } - foreach (KeyValuePair> keyValuePair in namedKeyValuePairs) - namedDeterministicHashCode.Add(keyValuePair.Key, keyValuePair.Value.Distinct().ToArray()); - foreach (KeyValuePair> keyValuePair in incorrectKeyValuePairs) - incorrectDeterministicHashCode.Add(keyValuePair.Key, keyValuePair.Value.Distinct().ToArray()); - } - - public void UpdateKeyValuePairs(List containers) - { - Dictionary> keyValuePairs = new(); - Dictionary namedDeterministicHashCode = new(); - Dictionary incorrectDeterministicHashCode = new(); - foreach (Container container in containers) - { - foreach (Item item in container.Items) - { - if (item.ImageFileHolder is null || item.Property?.Id is null || !item.Faces.Any()) - continue; - if (keyValuePairs.ContainsKey(item.Property.Id.Value)) - { - if (keyValuePairs[item.Property.Id.Value].Count != item.Faces.Count) - throw new Exception(); - continue; - } - keyValuePairs.Add(item.Property.Id.Value, item.Faces); - } - } - SetKeyValuePairs(_DeterministicHashCodeRootDirectory, namedDeterministicHashCode, incorrectDeterministicHashCode, keyValuePairs); - foreach (KeyValuePair keyValuePair in namedDeterministicHashCode) - _NamedDeterministicHashCodeKeyValuePairs.Add(keyValuePair.Key, keyValuePair.Value); - foreach (KeyValuePair keyValuePair in incorrectDeterministicHashCode) - _IncorrectDeterministicHashCodeKeyValuePairs.Add(keyValuePair.Key, keyValuePair.Value); - } - - public override string ToString() - { - string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); - return result; - } - - private long LogDelta(long ticks, string methodName) - { - long result; - if (_Log is null) - throw new NullReferenceException(nameof(_Log)); - double delta = new TimeSpan(DateTime.Now.Ticks - ticks).TotalMilliseconds; - _Log.Debug($"{methodName} took {Math.Floor(delta)} millisecond(s)"); - result = DateTime.Now.Ticks; - return result; - } - - public static List GetMetadataDateTimesByPattern(string dateTimeFormat, string filteredSourceDirectoryFile) - { - List results = new(); - try - { - DateTime checkDateTime; - DateTime kristy = new(1976, 3, 8); - IReadOnlyList directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(filteredSourceDirectoryFile); - foreach (MetadataExtractor.Directory directory in directories) - { - foreach (MetadataExtractor.Tag tag in directory.Tags) - { - if (string.IsNullOrEmpty(tag.Description) || tag.Description.Length != dateTimeFormat.Length) - continue; - if (!DateTime.TryParseExact(tag.Description, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) - continue; - if (checkDateTime < kristy) - continue; - results.Add(checkDateTime); - } - } - } - catch (Exception) { } - return results; - } - - public static List GetMetadataDateTimesByPattern(string dateTimeFormat, FileHolder filteredSourceDirectoryFileHolder) - { - List results = GetMetadataDateTimesByPattern(dateTimeFormat, filteredSourceDirectoryFileHolder.FullName); - return results; - } - -#pragma warning disable CA1416 - - private A_Property GetImageProperty(FileHolder filteredSourceDirectoryFileHolder, bool populateId, bool isIgnoreExtension, bool isValidImageFormatExtension, bool isValidMetadataExtensions, int? id, List indices) - { - A_Property result; - if (_Log is null) - throw new NullReferenceException(nameof(_Log)); - if (_Configuration.WriteBitmapDataBytes is null) - throw new NullReferenceException(nameof(_Configuration.WriteBitmapDataBytes)); - long ticks; - byte[] bytes; - string value; - long fileLength; - int encodingHash; - int? width = null; - int? height = null; - string dateTimeFormat; - DateTime checkDateTime; - DateTime? dateTime = null; - PropertyItem? propertyItem; - string make = string.Empty; - string model = string.Empty; - DateTime? gpsDateStamp = null; - DateTime? dateTimeOriginal = null; - string orientation = string.Empty; - DateTime? dateTimeDigitized = null; - if (!isValidImageFormatExtension && isValidMetadataExtensions) - { - dateTimeFormat = "ddd MMM dd HH:mm:ss yyyy"; - List dateTimes = GetMetadataDateTimesByPattern(dateTimeFormat, filteredSourceDirectoryFileHolder); - if (dateTimes.Any()) - dateTimeOriginal = dateTimes.Min(); - } - else if (!isIgnoreExtension && isValidImageFormatExtension) - { - if (populateId && (id is null || !indices.Any()) && !_IndicesFromNew.Any() && !_KeyValuePairs.Any()) - throw new Exception("In order to keep six character indices at least one need to have an item!"); - try - { - using Image image = Image.FromFile(filteredSourceDirectoryFileHolder.FullName); - if (populateId && (id is null || !indices.Any())) - { - using Bitmap bitmap = new(image); - string angleBracket = AngleBracketCollection[0]; - Rectangle rectangle = new(0, 0, image.Width, image.Height); - BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, bitmap.PixelFormat); - IntPtr intPtr = bitmapData.Scan0; - int length = bitmapData.Stride * bitmap.Height; - bytes = new byte[length]; - Marshal.Copy(intPtr, bytes, 0, length); - bitmap.UnlockBits(bitmapData); - if (id is null) - { - ticks = DateTime.Now.Ticks; - id = Stateless.A_Property.GetDeterministicHashCode(bytes); - if (_MaxDegreeOfParallelism < 2) - ticks = LogDelta(ticks, nameof(Stateless.A_Property.GetDeterministicHashCode)); - } - if (_Configuration.WriteBitmapDataBytes.Value) - { - FileInfo contentFileInfo = new(Path.Combine(angleBracket.Replace("<>", "()"), filteredSourceDirectoryFileHolder.Name)); - File.WriteAllBytes(Path.ChangeExtension(contentFileInfo.FullName, string.Empty), bytes); - } - if (_IndicesFromNew.ContainsKey(id.Value) && _IndicesFromNew[id.Value].Any()) - indices.AddRange(_IndicesFromNew[id.Value]); - else - { - ticks = DateTime.Now.Ticks; - string encoding = Encoding.Default.GetString(bytes); - if (_MaxDegreeOfParallelism < 2) - ticks = LogDelta(ticks, nameof(Encoding.Default.GetString)); - encodingHash = Stateless.A_Property.GetDeterministicHashCode(encoding); - if (_MaxDegreeOfParallelism < 2) - ticks = LogDelta(ticks, nameof(Stateless.A_Property.GetDeterministicHashCode)); - if (!_KeyValuePairs.ContainsKey(encodingHash)) - indices.Add(encodingHash); - else - indices.AddRange(_KeyValuePairs[encodingHash]); - } - } - width = image.Width; - height = image.Height; - dateTimeFormat = Stateless.A_Property.DateTimeFormat(); - if (image.PropertyIdList.Contains((int)IExif.Tags.DateTime)) - { - propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTime); - if (propertyItem?.Value is not null) - { - value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); - if (value.Length > dateTimeFormat.Length) - value = value[..dateTimeFormat.Length]; - if (value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) - dateTime = checkDateTime; - } - } - if (image.PropertyIdList.Contains((int)IExif.Tags.DateTimeDigitized)) - { - propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTimeDigitized); - if (propertyItem?.Value is not null) - { - value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); - if (value.Length > dateTimeFormat.Length) - value = value[..dateTimeFormat.Length]; - if (value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) - dateTimeDigitized = checkDateTime; - } - } - if (image.PropertyIdList.Contains((int)IExif.Tags.DateTimeOriginal)) - { - propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTimeOriginal); - if (propertyItem?.Value is not null) - { - value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); - if (value.Length > dateTimeFormat.Length) - value = value[..dateTimeFormat.Length]; - if (value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) - dateTimeOriginal = checkDateTime; - } - } - if (image.PropertyIdList.Contains((int)IExif.Tags.GPSDateStamp)) - { - propertyItem = image.GetPropertyItem((int)IExif.Tags.GPSDateStamp); - if (propertyItem?.Value is not null) - { - value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); - if (value.Length > dateTimeFormat.Length) - value = value[..dateTimeFormat.Length]; - if (value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) - gpsDateStamp = checkDateTime; - } - } - if (image.PropertyIdList.Contains((int)IExif.Tags.Make)) - { - propertyItem = image.GetPropertyItem((int)IExif.Tags.Make); - if (propertyItem?.Value is not null) - { - value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); - make = value; - } - } - if (image.PropertyIdList.Contains((int)IExif.Tags.Model)) - { - propertyItem = image.GetPropertyItem((int)IExif.Tags.Model); - if (propertyItem?.Value is not null) - { - value = _ASCIIEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1); - model = value; - } - } - if (image.PropertyIdList.Contains((int)IExif.Tags.Orientation)) - { - propertyItem = image.GetPropertyItem((int)IExif.Tags.Orientation); - if (propertyItem?.Value is not null) - { - value = BitConverter.ToInt16(propertyItem.Value, 0).ToString(); - orientation = value; - } - } - } - catch (Exception) - { - _Log.Info(string.Concat(new StackFrame().GetMethod()?.Name, " <", filteredSourceDirectoryFileHolder.Name, ">")); - } - } - else - dateTimeOriginal = null; - if (filteredSourceDirectoryFileHolder.Length is null) - fileLength = 0; - else - fileLength = filteredSourceDirectoryFileHolder.Length.Value; - result = new(filteredSourceDirectoryFileHolder.CreationTime, dateTime, dateTimeDigitized, dateTimeOriginal, fileLength, gpsDateStamp, height, id, indices.ToArray(), filteredSourceDirectoryFileHolder.LastWriteTime, make, model, orientation, width); - return result; - } - -#pragma warning restore CA1416 - - private A_Property GetPropertyOfPrivate(Item item, bool firstPass, List> filteredSourceDirectoryFileTuples, List parseExceptions, bool isIgnoreExtension, bool isValidMetadataExtensions) - { - A_Property? result; - if (_Configuration.ForcePropertyLastWriteTimeToCreationTime is null) - throw new NullReferenceException(nameof(_Configuration.ForcePropertyLastWriteTimeToCreationTime)); - if (_Configuration.PopulatePropertyId is null) - throw new NullReferenceException(nameof(_Configuration.PopulatePropertyId)); - if (_Configuration.PropertiesChangedForProperty is null) - throw new NullReferenceException(nameof(_Configuration.PropertiesChangedForProperty)); - if (item.ImageFileHolder is null) - throw new NullReferenceException(nameof(item.ImageFileHolder)); - string json; - int? id = null; - List indices = new(); - bool hasWrongYearProperty = false; - string[] changesFrom = Array.Empty(); - string angleBracket = AngleBracketCollection[0]; - bool populateId = !firstPass && _Configuration.PopulatePropertyId.Value; - string without = Path.Combine(angleBracket.Replace("<>", "{}"), $"{item.ImageFileHolder.NameWithoutExtension}.json"); - FileInfo fileInfo = new(Path.Combine(angleBracket.Replace("<>", "{}"), $"{item.ImageFileHolder.NameWithoutExtension}{item.ImageFileHolder.ExtensionLowered}.json")); - if (item.ValidImageFormatExtension && File.Exists(without)) - { - File.Move(without, fileInfo.FullName); - fileInfo.Refresh(); - } - List dateTimes = (from l in filteredSourceDirectoryFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); - if (!fileInfo.Exists) - { - if (fileInfo.Directory?.Parent is null) - throw new Exception(); - string parentCheck = Path.Combine(fileInfo.Directory.Parent.FullName, fileInfo.Name); - if (File.Exists(parentCheck)) - { - File.Move(parentCheck, fileInfo.FullName); - fileInfo.Refresh(); - } - } - if (_Configuration.ForcePropertyLastWriteTimeToCreationTime.Value && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete"))) - { - File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName); - fileInfo.Refresh(); - } - if (_Configuration.ForcePropertyLastWriteTimeToCreationTime.Value && fileInfo.Exists && fileInfo.LastWriteTime != fileInfo.CreationTime) - { - File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime); - fileInfo.Refresh(); - } - if (_Configuration.PropertiesChangedForProperty.Value) - result = null; - else if (!fileInfo.Exists) - result = null; - else if (!fileInfo.FullName.EndsWith(".json") && !fileInfo.FullName.EndsWith(".old")) - throw new ArgumentException("must be a *.json file"); - else if (dateTimes.Any() && dateTimes.Max() > fileInfo.LastWriteTime) - result = null; - else - { - json = File.ReadAllText(fileInfo.FullName); - try - { - if (item.ImageFileHolder is null) - throw new NullReferenceException(nameof(item.ImageFileHolder)); - bool check = true; - A_Property? property = JsonSerializer.Deserialize(json); - if (!isIgnoreExtension && item.ValidImageFormatExtension && ((populateId && property?.Id is null) || property?.Width is null || property?.Height is null)) - { - check = false; - id = property?.Id; - if (property is not null && property.Indices.Any()) - indices = property.Indices.ToList(); - property = GetImageProperty(item.ImageFileHolder, populateId, isIgnoreExtension, item.ValidImageFormatExtension, isValidMetadataExtensions, id, indices); - } - if (!isIgnoreExtension && item.ValidImageFormatExtension && populateId && property is not null && !property.Indices.Any()) - { - check = false; - id = property?.Id; - if (property is not null && property.Indices.Any()) - indices = property.Indices.ToList(); - property = GetImageProperty(item.ImageFileHolder, populateId, isIgnoreExtension, item.ValidImageFormatExtension, isValidMetadataExtensions, id, indices); - } - if (!isIgnoreExtension && item.ValidImageFormatExtension && populateId && property is not null && property.LastWriteTime != item.ImageFileHolder.LastWriteTime) - { - check = false; - id = null; - indices.Clear(); - property = GetImageProperty(item.ImageFileHolder, populateId, isIgnoreExtension, item.ValidImageFormatExtension, isValidMetadataExtensions, id, indices); - } - if (!isIgnoreExtension && item.ValidImageFormatExtension && property?.Width is not null && property?.Height is not null && property.Width.Value == property.Height.Value && item.ImageFileHolder.Exists) - { - check = false; - id = property?.Id; - if (property is not null && property.Indices.Any()) - indices = property.Indices.ToList(); - property = GetImageProperty(item.ImageFileHolder, populateId, isIgnoreExtension, item.ValidImageFormatExtension, isValidMetadataExtensions, id, indices); - if (property?.Width is not null && property?.Height is not null && property.Width.Value != property.Height.Value) - throw new Exception("Was square!"); - } - // if (filteredSourceDirectoryFileFileInfo.CreationTime != property?.CreationTime || filteredSourceDirectoryFileFileInfo.LastWriteTime != property?.LastWriteTime) - // { - // check = false; - // id = null; - // indices.Clear(); - // property = GetImagePropertyB(filteredSourceDirectoryFile, populateId, isIgnoreExtension, isValidImageFormatExtension, isValidMetadataExtensions, id, indices); - // } - if (json.Contains("WrongYear")) - { - id = property?.Id; - hasWrongYearProperty = true; - } - if (property is null) - throw new Exception(); - if (!check) - result = null; - else - { - result = property; - filteredSourceDirectoryFileTuples.Add(new Tuple(nameof(A_Property), fileInfo.LastWriteTime)); - } - } - catch (Exception) - { - result = null; - parseExceptions.Add(nameof(A_Property)); - } - } - if (result is null) - { - if (item.ImageFileHolder is null) - throw new NullReferenceException(nameof(item.ImageFileHolder)); - result = GetImageProperty(item.ImageFileHolder, populateId, isIgnoreExtension, item.ValidImageFormatExtension, isValidMetadataExtensions, id, indices); - json = JsonSerializer.Serialize(result, _WriteIndentedJsonSerializerOptions); - if (populateId && IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true)) - { - if (!_Configuration.ForcePropertyLastWriteTimeToCreationTime.Value && (!fileInfo.Exists || fileInfo.LastWriteTime == fileInfo.CreationTime)) - filteredSourceDirectoryFileTuples.Add(new Tuple(nameof(A_Property), DateTime.Now)); - else - { - File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime); - fileInfo.Refresh(); - filteredSourceDirectoryFileTuples.Add(new Tuple(nameof(A_Property), fileInfo.CreationTime)); - } - } - } - else if (hasWrongYearProperty) - { - json = JsonSerializer.Serialize(result, _WriteIndentedJsonSerializerOptions); - if (IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true)) - { - File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime); - fileInfo.Refresh(); - filteredSourceDirectoryFileTuples.Add(new Tuple(nameof(A_Property), fileInfo.CreationTime)); - } - } - return result; - } - - private bool AnyFilesMoved(string sourceDirectory, Item[] filteredItems) - { - bool result = false; - if (_Log is null) - throw new NullReferenceException(nameof(_Log)); - int season; - string[] matches; - string deleteFile; - bool? isWrongYear; - string seasonName; - DateTime dateTime; - string destinationFile; - DateTime minimumDateTime; - string destinationDirectory; - string[] sourceDirectorySegments; - DateTime directoryMaximumOfMinimumDateTime = DateTime.MinValue; - foreach (Item filteredItem in filteredItems) - { - if (!filteredItem.ValidImageFormatExtension || filteredItem.Property is null || filteredItem.ImageFileHolder is null) - continue; - minimumDateTime = Stateless.A_Property.GetMinimumDateTime(filteredItem.Property); - if (minimumDateTime > directoryMaximumOfMinimumDateTime) - directoryMaximumOfMinimumDateTime = minimumDateTime; - if (minimumDateTime != filteredItem.ImageFileHolder.CreationTime) - { - (isWrongYear, matches) = filteredItem.Property.IsWrongYear(filteredItem.ImageFileHolder.FullName, minimumDateTime); - if (isWrongYear is null || !isWrongYear.Value) - dateTime = minimumDateTime; - else - { - if (!matches.Any()) - continue; - if (!DateTime.TryParseExact(matches[0], "yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) - continue; - } - try - { File.SetCreationTime(filteredItem.ImageFileHolder.FullName, dateTime); } - catch (Exception) - { } - } - if (!_VerifyToSeason.Contains(sourceDirectory)) - continue; - if (!filteredItem.ImageFileHolder.FullName.Contains("zzz ") && !filteredItem.ImageFileHolder.FullName.Contains("Camera ") && filteredItem.Property.DateTimeOriginal.HasValue) - { - TimeSpan timeSpan = new(filteredItem.Property.DateTimeOriginal.Value.Ticks - filteredItem.Property.LastWriteTime.Ticks); - if (timeSpan.TotalHours > 6) - { - _Log.Warning($"*** propertyHolder.FileInfo.FullName <{filteredItem.ImageFileHolder.FullName}>"); - _Log.Warning($"*** DateTimeOriginal <{filteredItem.Property.DateTimeOriginal.Value}>"); - _Log.Warning($"*** LastWriteTime <{filteredItem.Property.LastWriteTime}>"); - _Log.Warning($"*** TotalHours <{timeSpan.TotalHours}>"); - } - } - sourceDirectorySegments = Path.GetFileName(sourceDirectory).Split(' '); - (season, seasonName) = Stateless.A_Property.GetSeason(minimumDateTime.DayOfYear); - if (sourceDirectorySegments[0] == "zzz") - destinationDirectory = Path.Combine(_Configuration.RootDirectory, $"zzz ={minimumDateTime:yyyy}.{season} {seasonName} {string.Join(' ', sourceDirectorySegments.Skip(3))}"); - else if (sourceDirectorySegments.Length > 2) - destinationDirectory = Path.Combine(_Configuration.RootDirectory, $"={minimumDateTime:yyyy}.{season} {seasonName} {string.Join(' ', sourceDirectorySegments.Skip(2))}"); - else - destinationDirectory = Path.Combine(_Configuration.RootDirectory, $"={minimumDateTime:yyyy}.{season} {seasonName}"); - if (destinationDirectory == sourceDirectory) - continue; - lock (filteredItem) - filteredItem.SetMoved(true); - if (!result) - result = true; - if (!Directory.Exists(destinationDirectory)) - _ = Directory.CreateDirectory(destinationDirectory); - destinationFile = Path.Combine(destinationDirectory, filteredItem.ImageFileHolder.Name); - if (File.Exists(destinationFile)) - { - if (destinationFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture)) - destinationFile = Path.Combine(destinationDirectory, Path.ChangeExtension(filteredItem.ImageFileHolder.Name, ".jpeg")); - else if (destinationFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture)) - destinationFile = Path.Combine(destinationDirectory, Path.ChangeExtension(filteredItem.ImageFileHolder.Name, ".jpg")); - } - if (File.Exists(destinationFile)) - { - _Log.Information($"*** source <{filteredItem.ImageFileHolder.FullName}>"); - _Log.Information($"*** destination <{destinationFile}>"); - if (filteredItem.ImageFileHolder.Exists) - { - deleteFile = Path.ChangeExtension(filteredItem.ImageFileHolder.FullName, ".delete"); - if (File.Exists(deleteFile)) - File.Delete(deleteFile); - File.Move(filteredItem.ImageFileHolder.FullName, deleteFile); - } - } - else - { - File.Move(filteredItem.ImageFileHolder.FullName, destinationFile); - if (filteredItem.ImageFileHolder.Exists) - { - deleteFile = Path.ChangeExtension(filteredItem.ImageFileHolder.FullName, ".delete"); - if (File.Exists(deleteFile)) - File.Delete(deleteFile); - File.Move(filteredItem.ImageFileHolder.FullName, deleteFile); - } - } - } - if (directoryMaximumOfMinimumDateTime != DateTime.MinValue) - { - System.IO.DirectoryInfo directoryInfo = new(sourceDirectory); - if (directoryInfo.LastWriteTime != directoryMaximumOfMinimumDateTime) - Directory.SetLastWriteTime(sourceDirectory, directoryMaximumOfMinimumDateTime); - } - return result; - } - - private void ParallelForWork(bool firstPass, string sourceDirectory, List> filteredSourceDirectoryFileTuples, List> sourceDirectoryChanges, Item item) - { - if (item.ImageFileHolder is null) - throw new NullReferenceException(nameof(item.ImageFileHolder)); - A_Property property; - List parseExceptions = new(); - bool isValidMetadataExtensions = _Configuration.ValidMetadataExtensions.Contains(item.ImageFileHolder.ExtensionLowered); - bool isIgnoreExtension = item.ValidImageFormatExtension && _Configuration.IgnoreExtensions.Contains(item.ImageFileHolder.ExtensionLowered); - string filteredSourceDirectoryFileExtensionLowered = Path.Combine(sourceDirectory, $"{item.ImageFileHolder.NameWithoutExtension}{item.ImageFileHolder.ExtensionLowered}"); - if (item.ValidImageFormatExtension && item.ImageFileHolder.FullName.Length == filteredSourceDirectoryFileExtensionLowered.Length && item.ImageFileHolder.FullName != filteredSourceDirectoryFileExtensionLowered) - File.Move(item.ImageFileHolder.FullName, filteredSourceDirectoryFileExtensionLowered); - if (item.Changed is null || item.Changed.Value || item.Property is null) - { - property = GetPropertyOfPrivate(item, firstPass, filteredSourceDirectoryFileTuples, parseExceptions, isIgnoreExtension, isValidMetadataExtensions); - lock (sourceDirectoryChanges) - sourceDirectoryChanges.Add(new Tuple(nameof(A_Property), DateTime.Now)); - lock (item) - item.Update(property); - } - } - - private void ParallelWork(bool firstPass, List exceptions, List> sourceDirectoryChanges, int containersCount, Container container, Item[] filteredItems, int totalSeconds) - { - List> filteredSourceDirectoryFileTuples = new(); - ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = _MaxDegreeOfParallelism }; - ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; - string message = $"{container.R:000}.{container.G} / {containersCount:000}) {filteredItems.Length:000} file(s) - {totalSeconds} total second(s) - {container.SourceDirectory}"; - using ProgressBar progressBar = new(filteredItems.Length, message, options); - _ = Parallel.For(0, filteredItems.Length, parallelOptions, i => - { - try - { - long ticks = DateTime.Now.Ticks; - DateTime dateTime = DateTime.Now; - List> collection; - ParallelForWork(firstPass, container.SourceDirectory, sourceDirectoryChanges, filteredSourceDirectoryFileTuples, filteredItems[i]); - if (i == 0 || sourceDirectoryChanges.Any()) - progressBar.Tick(); - lock (filteredSourceDirectoryFileTuples) - collection = (from l in filteredSourceDirectoryFileTuples where l.Item2 > dateTime select l).ToList(); - lock (sourceDirectoryChanges) - sourceDirectoryChanges.AddRange(collection); - } - catch (Exception ex) - { - lock (exceptions) - exceptions.Add(ex); - } - }); - } - - private void SetAngleBracketCollection(string sourceDirectory) - { - AngleBracketCollection.Clear(); - AngleBracketCollection.AddRange(IResult.GetDirectoryInfoCollection(_Configuration, - _Model, - _PredictorModel, - sourceDirectory, - nameof(A_Property), - string.Empty, - includeResizeGroup: false, - includeModel: false, - includePredictorModel: false, - contentDescription: string.Empty, - singletonDescription: "Properties for each image", - collectionDescription: string.Empty)); - } - - public void ParallelWork(long ticks, List containers, bool firstPass) - { - if (_Log is null) - throw new NullReferenceException(nameof(_Log)); - if (_Configuration.PopulatePropertyId is null) - throw new NullReferenceException(nameof(_Configuration.PopulatePropertyId)); - int totalSeconds; - bool? anyFilesMoved; - Item[] filteredItems; - List exceptions = new(); - int containersCount = containers.Count; - List> sourceDirectoryChanges = new(); - string propertyRoot = IResult.GetResultsGroupDirectory(_Configuration, nameof(A_Property)); - foreach (Container container in containers) - { - if (!container.Items.Any()) - continue; - sourceDirectoryChanges.Clear(); - if (firstPass) - filteredItems = (from l in container.Items where l.NoJson is null || !l.NoJson.Value && (l.Changed is null || l.Changed.Value) select l).ToArray(); - else - filteredItems = (from l in container.Items where l.ImageFileHolder is not null && !_Configuration.IgnoreExtensions.Contains(l.ImageFileHolder.ExtensionLowered) select l).ToArray(); - if (!filteredItems.Any()) - continue; - totalSeconds = (int)Math.Truncate(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); - SetAngleBracketCollection(container.SourceDirectory); - ParallelWork(firstPass, exceptions, sourceDirectoryChanges, containersCount, container, filteredItems, totalSeconds); - foreach (Exception exception in exceptions) - _Log.Error(string.Concat(container.SourceDirectory, Environment.NewLine, exception.Message, Environment.NewLine, exception.StackTrace), exception); - if (exceptions.Count == filteredItems.Length) - throw new Exception(string.Concat("All in [", container.SourceDirectory, "]failed!")); - if (exceptions.Count != 0) - _ExceptionsDirectories.Add(container.SourceDirectory); - if (!firstPass || exceptions.Count != 0) - anyFilesMoved = null; - else - anyFilesMoved = AnyFilesMoved(container.SourceDirectory, filteredItems); - if (Directory.GetFiles(propertyRoot, "*.txt", SearchOption.TopDirectoryOnly).Any()) - { - for (int y = 0; y < int.MaxValue; y++) - { - _Log.Information("Press \"Y\" key when ready to continue or close console"); - if (Console.ReadKey().Key == ConsoleKey.Y) - break; - } - _Log.Information(". . ."); - } - } - } - - public A_Property GetProperty(Item item, List> filteredSourceDirectoryFileTuples, List parseExceptions) - { - A_Property result; - if (item.ImageFileHolder is null) - throw new NullReferenceException(nameof(item.ImageFileHolder)); - bool firstPass = false; - bool isValidMetadataExtensions = _Configuration.ValidMetadataExtensions.Contains(item.ImageFileHolder.ExtensionLowered); - bool isIgnoreExtension = item.ValidImageFormatExtension && _Configuration.IgnoreExtensions.Contains(item.ImageFileHolder.ExtensionLowered); - result = GetPropertyOfPrivate(item, firstPass, filteredSourceDirectoryFileTuples, parseExceptions, isIgnoreExtension, isValidMetadataExtensions); - return result; - } - - public (long Ticks, string FilteredSourceDirectoryFile, string PropertyDirectory, int PropertyId)[] GetPropertyIds(List groupCollection, bool saveToCollection) - { - List<(long Ticks, string FilteredSourceDirectoryFile, string PropertyDirectory, int PropertyId)> results = new(); - int level; - A_Property? property; - string checkDirectory; - List directories; - string propertyDirectory; - string angleBracket = AngleBracketCollection[0]; - foreach (DirectoryInfo group in groupCollection) - { - SetAngleBracketCollection(group.SourceDirectory); - if (string.IsNullOrEmpty(group.SourceDirectory)) - throw new Exception(); - if (!saveToCollection) - propertyDirectory = angleBracket.Replace("<>", "()"); - else - { - (level, directories) = IPath.Get(_Configuration.RootDirectory, group.SourceDirectory); - checkDirectory = IPath.GetDirectory(angleBracket, level, "[()]"); - propertyDirectory = Path.Combine(checkDirectory, string.Join(_Configuration.FileNameDirectorySeparator, directories)); - } - if (!Directory.Exists(propertyDirectory)) - _ = Directory.CreateDirectory(propertyDirectory); - for (int i = 0; i < group.SourceDirectoryFileHolderCollection.Length; i++) - { - property = group.PropertyCollection[i]; - if (property?.Id is null) - continue; - results.Add(new(property.GetDateTimes().Min().Ticks, group.FilteredSourceDirectoryFiles[i], propertyDirectory, property.Id.Value)); - } - } - return results.OrderBy(l => l.Ticks).ToArray(); - } - - public void AddToPropertyLogicAllCollection(Item[] filteredItems) - { - if (_SixCharacterNamedFaceInfo.Any()) - { - string[] keys; - Item item; - for (int i = 0; i < filteredItems.Length; i++) - { - item = filteredItems[i]; - if (item.Property?.Id is null) - continue; - foreach (int sixCharacterIndex in item.Property.Indices) - { - if (!_SixCharacterNamedFaceInfo.ContainsKey(sixCharacterIndex)) - continue; - keys = _SixCharacterNamedFaceInfo[sixCharacterIndex]; - _AllCollection.Add(new(item.Property.Id.Value, keys)); - } - } - } - } - - public void SaveAllCollection() - { - if (_AllCollection.Any()) - { - string[] keys; - string? rootDirectoryParent = Path.GetDirectoryName(_Configuration.RootDirectory); - if (string.IsNullOrEmpty(rootDirectoryParent)) - throw new NullReferenceException(nameof(rootDirectoryParent)); - Dictionary namedFaceInfoDeterministicHashCodeIndices = new(); - List<(int, string[])> allCollection = _AllCollection.OrderBy(l => l.Item1).ToList(); - foreach ((int deterministicHashCode, string[] values) in allCollection) - { - if (namedFaceInfoDeterministicHashCodeIndices.ContainsKey(deterministicHashCode)) - { - keys = namedFaceInfoDeterministicHashCodeIndices[deterministicHashCode]; - if (JsonSerializer.Serialize(values) == JsonSerializer.Serialize(keys)) - continue; - throw new Exception(); - } - namedFaceInfoDeterministicHashCodeIndices.Add(deterministicHashCode, values); - } - string json = JsonSerializer.Serialize(namedFaceInfoDeterministicHashCodeIndices, new JsonSerializerOptions { WriteIndented = true }); - string checkFile = Path.Combine(rootDirectoryParent, "NamedFaceInfoDeterministicHashCodeIndices.json"); - _ = IPath.WriteAllText(checkFile, json, updateDateWhenMatches: true, compareBeforeWrite: true); - } - } - -} \ No newline at end of file diff --git a/Property/Models/Stateless/Configuration.cs b/Property/Models/Stateless/Configuration.cs deleted file mode 100644 index 25574b2..0000000 --- a/Property/Models/Stateless/Configuration.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Microsoft.Extensions.Configuration; -using Phares.Shared; -using System.Text.Json; - -namespace View_by_Distance.Property.Models.Stateless; - -public abstract class Configuration -{ - - public static Models.Configuration Get(IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, string workingDirectory) - { - Models.Configuration? result; - string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); - string section = string.Concat(environmentName, ":", nameof(Binder.Configuration)); - IConfigurationSection configurationSection = configurationRoot.GetSection(section); - Binder.Configuration configuration = configurationSection.Get(); - string json = JsonSerializer.Serialize(configuration, new JsonSerializerOptions() { WriteIndented = true }); - result = JsonSerializer.Deserialize(json); - if (result is null) - throw new Exception(json); - string jsonThis = result.ToString(); - if (jsonThis != json) - { - int? check = null; - int min = new int[] { json.Length, jsonThis.Length }.Min(); - for (int i = 0; i < min; i++) - { - if (json[i] == jsonThis[i]) - continue; - check = i; - break; - } - if (check is null) - throw new Exception(); - string a = json[..check.Value].Split(',')[^1]; - string b = json[check.Value..].Split(',')[0]; - throw new Exception($"{a}{b}"); - } - return result; - } - -} \ No newline at end of file diff --git a/Property/Models/Stateless/Container.cs b/Property/Models/Stateless/Container.cs index 881a1ad..78d3565 100644 --- a/Property/Models/Stateless/Container.cs +++ b/Property/Models/Stateless/Container.cs @@ -1,4 +1,5 @@ using System.Text.Json; +using View_by_Distance.Shared.Models; namespace View_by_Distance.Property.Models.Stateless; @@ -98,67 +99,61 @@ public class Container return results; } - private static List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> GetJsonGroupCollection(Models.Configuration configuration, PropertyLogic propertyLogic, string rootDirectory) + private static List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> GetJsonGroupCollection(Configuration configuration, A_Property propertyLogic, string rootDirectory) { List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> results; - if (configuration.MaxImagesInDirectoryForTopLevelFirstPass is null) - throw new NullReferenceException(nameof(configuration.MaxImagesInDirectoryForTopLevelFirstPass)); string searchPattern = "*.json"; List topDirectories = new(); - results = GetGroupCollection(rootDirectory, configuration.MaxImagesInDirectoryForTopLevelFirstPass.Value, propertyLogic.Reverse, searchPattern, topDirectories); + results = GetGroupCollection(rootDirectory, configuration.MaxImagesInDirectoryForTopLevelFirstPass, propertyLogic.Reverse, searchPattern, topDirectories); return results; } - private static List<(int g, string sourceDirectory, FileHolder[] sourceDirectoryFiles, int r)> GetFileHolderGroupCollection(Models.Configuration configuration, PropertyLogic propertyLogic, string searchPattern, List topDirectories) + private static List<(int g, string sourceDirectory, FileHolder[] sourceDirectoryFiles, int r)> GetFileHolderGroupCollection(Configuration configuration, A_Property propertyLogic, string searchPattern, List topDirectories) { List<(int g, string sourceDirectory, FileHolder[] sourceDirectoryFiles, int r)> results = new(); - if (configuration.MaxImagesInDirectoryForTopLevelFirstPass is null) - throw new NullReferenceException(nameof(configuration.MaxImagesInDirectoryForTopLevelFirstPass)); - List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)>? collection = GetGroupCollection(configuration.RootDirectory, configuration.MaxImagesInDirectoryForTopLevelFirstPass.Value, propertyLogic.Reverse, searchPattern, topDirectories); + List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)>? collection = GetGroupCollection(configuration.RootDirectory, configuration.MaxImagesInDirectoryForTopLevelFirstPass, propertyLogic.Reverse, searchPattern, topDirectories); foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles, int r) in collection) results.Add(new(g, sourceDirectory, (from l in sourceDirectoryFiles select new FileHolder(l)).ToArray(), r)); return results; } - private static void ParallelFor(List<(int, string, string[], int)> jsonCollection, int i, int length, List<(int, string, List<(string, Models.A_Property?)>, int)> results) + private static void ParallelFor(List<(int, string, string[], int)> jsonCollection, int i, int length, List<(int, string, List<(string, Shared.Models.Property?)>, int)> results) { string key; string json; - Models.A_Property? property; + Shared.Models.Property? property; (int g, string sourceDirectory, string[] sourceDirectoryFiles, int r) = jsonCollection[i]; - List<(string, Models.A_Property?)> collection = new(); + List<(string, Shared.Models.Property?)> collection = new(); foreach (string sourceDirectoryFile in sourceDirectoryFiles) { json = File.ReadAllText(sourceDirectoryFile); - key = XPath.GetRelativePath(sourceDirectoryFile, length); - property = JsonSerializer.Deserialize(json); + key = Shared.Models.Stateless.Methods.IPath.GetRelativePath(sourceDirectoryFile, length); + property = JsonSerializer.Deserialize(json); collection.Add(new(sourceDirectoryFile, property)); } lock (results) results.Add(new(g, sourceDirectory, collection, r)); } - private static List<(int g, string sourceDirectory, List<(string sourceDirectoryFile, Models.A_Property? property)> collection, int r)> GetCollection(string rootDirectory, List<(int g, string sourceDirectory, string[] SourceDirectoryFiles, int r)> jsonCollection) + private static List<(int g, string sourceDirectory, List<(string sourceDirectoryFile, Shared.Models.Property? property)> collection, int r)> GetCollection(string rootDirectory, List<(int g, string sourceDirectory, string[] SourceDirectoryFiles, int r)> jsonCollection) { - List<(int, string, List<(string, Models.A_Property?)>, int)> results = new(); + List<(int, string, List<(string, Shared.Models.Property?)>, int)> results = new(); int length = rootDirectory.Length; ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = Environment.ProcessorCount }; _ = Parallel.For(0, jsonCollection.Count, parallelOptions, i => ParallelFor(jsonCollection, i, length, results)); return results; } - private static List GetContainers(Models.Configuration configuration, string aPropertySingletonDirectory, List<(int, string, FileHolder[], int)> fileHolderGroupCollection, List<(int, string, List<(string, Models.A_Property?)>, int)> collectionFromJson) + private static List GetContainers(Configuration configuration, string aPropertySingletonDirectory, List<(int, string, FileHolder[], int)> fileHolderGroupCollection, List<(int, string, List<(string, Shared.Models.Property?)>, int)> collectionFromJson) { - List results = new(); - if (configuration.PropertiesChangedForProperty is null) - throw new Exception($"{configuration.PropertiesChangedForProperty} is null"); + List results = new(); int length; string key; string inferred; List items; string relativePath; FileHolder keyFileHolder; - Models.Container container; + Shared.Models.Container container; bool isValidImageFormatExtension; List keySourceDirectories; Dictionary fileHolderKeyValuePairs = new(); @@ -167,21 +162,21 @@ public class Container { foreach (FileHolder sourceDirectoryFileHolder in sourceDirectoryFileHolderCollection) { - relativePath = XPath.GetRelativePath(sourceDirectoryFileHolder.FullName, length); + relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(sourceDirectoryFileHolder.FullName, length); key = string.Concat(relativePath, ".json"); fileHolderKeyValuePairs.Add(key, new(sourceDirectory, sourceDirectoryFileHolder)); } } length = aPropertySingletonDirectory.Length; - foreach ((int g, string _, List<(string, Models.A_Property?)> collection, int r) in collectionFromJson) + foreach ((int g, string _, List<(string, Shared.Models.Property?)> collection, int r) in collectionFromJson) { if (!collection.Any()) continue; items = new(); keySourceDirectories = new(); - foreach ((string sourceDirectoryFile, Models.A_Property? property) in collection) + foreach ((string sourceDirectoryFile, Shared.Models.Property? property) in collection) { - key = XPath.GetRelativePath(sourceDirectoryFile, length); + key = Shared.Models.Stateless.Methods.IPath.GetRelativePath(sourceDirectoryFile, length); relativePath = key[..^5]; if (!fileHolderKeyValuePairs.ContainsKey(key)) { @@ -204,7 +199,7 @@ public class Container isValidImageFormatExtension = configuration.ValidImageFormatExtensions.Contains(keyFileHolder.ExtensionLowered); if (property?.Id is null || property?.Width is null || property?.Height is null) items.Add(new(sourceDirectoryFile, relativePath, keyFileHolder, isValidImageFormatExtension, property, false, null)); - else if (configuration.PropertiesChangedForProperty.Value || property.LastWriteTime != keyFileHolder.LastWriteTime || property.FileSize != keyFileHolder.Length) + else if (configuration.PropertiesChangedForProperty || property.LastWriteTime != keyFileHolder.LastWriteTime || property.FileSize != keyFileHolder.Length) items.Add(new(sourceDirectoryFile, relativePath, keyFileHolder, isValidImageFormatExtension, property, false, true)); else items.Add(new(sourceDirectoryFile, relativePath, keyFileHolder, isValidImageFormatExtension, property, false, false)); @@ -224,7 +219,7 @@ public class Container items = new(); foreach (FileHolder sourceDirectoryFileHolder in sourceDirectoryFileHolderCollection) { - relativePath = XPath.GetRelativePath(sourceDirectoryFileHolder.FullName, length); + relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(sourceDirectoryFileHolder.FullName, length); key = string.Concat(relativePath, ".json"); if (!fileHolderKeyValuePairs.ContainsKey(key)) continue; @@ -247,16 +242,15 @@ public class Container return results; } - public static List GetContainers(Models.Configuration configuration, PropertyLogic propertyLogic) + public static List GetContainers(Configuration configuration, A_Property propertyLogic) { - List results; + List results; string searchPattern = "*"; - long ticks = DateTime.Now.Ticks; List topDirectories = new(); List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> jsonCollection; List<(int g, string sourceDirectory, FileHolder[] sourceDirectoryFiles, int r)> fileHolderGroupCollection; string aPropertySingletonDirectory = IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}"); - List<(int g, string sourceDirectory, List<(string sourceDirectoryFile, Models.A_Property? property)> collection, int r)> collectionFromJson; + List<(int g, string sourceDirectory, List<(string sourceDirectoryFile, Shared.Models.Property? property)> collection, int r)> collectionFromJson; jsonCollection = GetJsonGroupCollection(configuration, propertyLogic, aPropertySingletonDirectory); fileHolderGroupCollection = GetFileHolderGroupCollection(configuration, propertyLogic, searchPattern, topDirectories); collectionFromJson = GetCollection(aPropertySingletonDirectory, jsonCollection); diff --git a/Property/Models/Stateless/IResult.cs b/Property/Models/Stateless/IResult.cs index 789900b..6b726e3 100644 --- a/Property/Models/Stateless/IResult.cs +++ b/Property/Models/Stateless/IResult.cs @@ -10,32 +10,32 @@ public interface IResult public const string Collection = "[]"; public const string AllInOne = "_ _ _"; - string TestStatic_GetRelativePath(Models.Configuration configuration, string path); - static string GetRelativePath(Models.Configuration configuration, string path) + string TestStatic_GetRelativePath(Configuration configuration, string path); + static string GetRelativePath(Configuration configuration, string path) => Result.GetRelativePath(configuration, path); - string TestStatic_GetResultsGroupDirectory(Models.Configuration configuration, string description); - static string GetResultsGroupDirectory(Models.Configuration configuration, string description) + string TestStatic_GetResultsGroupDirectory(Configuration configuration, string description); + static string GetResultsGroupDirectory(Configuration configuration, string description) => Result.GetResultsGroupDirectory(configuration, description); - string TestStatic_GetResultsDateGroupDirectory(Models.Configuration configuration, string description); - static string GetResultsDateGroupDirectory(Models.Configuration configuration, string description) + string TestStatic_GetResultsDateGroupDirectory(Configuration configuration, string description); + static string GetResultsDateGroupDirectory(Configuration configuration, string description) => Result.GetResultsDateGroupDirectory(configuration, description); - string TestStatic_GetResultsDateGroupDirectory(Models.Configuration configuration, string description, string jsonGroup); - static string GetResultsDateGroupDirectory(Models.Configuration configuration, string description, string jsonGroup) + string TestStatic_GetResultsDateGroupDirectory(Configuration configuration, string description, string jsonGroup); + static string GetResultsDateGroupDirectory(Configuration configuration, string description, string jsonGroup) => Result.GetResultsDateGroupDirectory(configuration, description, jsonGroup); - List TestStatic_GetDirectoryInfoCollection(Models.Configuration configuration, string sourceDirectory, string dateGroupDirectory, string contentDescription, string singletonDescription, string collectionDescription); - static List GetDirectoryInfoCollection(Models.Configuration configuration, string sourceDirectory, string dateGroupDirectory, string contentDescription, string singletonDescription, string collectionDescription, bool converted) + List TestStatic_GetDirectoryInfoCollection(Configuration configuration, string sourceDirectory, string dateGroupDirectory, string contentDescription, string singletonDescription, string collectionDescription); + static List GetDirectoryInfoCollection(Configuration configuration, string sourceDirectory, string dateGroupDirectory, string contentDescription, string singletonDescription, string collectionDescription, bool converted) => Result.GetDirectoryInfoCollection(configuration, sourceDirectory, dateGroupDirectory, contentDescription, singletonDescription, collectionDescription, converted); - string TestStatic_GetResultsFullGroupDirectory(Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel); - static string GetResultsFullGroupDirectory(Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel) + string TestStatic_GetResultsFullGroupDirectory(Configuration configuration, Model? model, PredictorModel? predictorModel, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel); + static string GetResultsFullGroupDirectory(Configuration configuration, Model? model, PredictorModel? predictorModel, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel) => Result.GetResultsFullGroupDirectory(configuration, model, predictorModel, description, outputResolution, includeResizeGroup, includeModel, includePredictorModel); - List TestStatic_GetDirectoryInfoCollection(Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string sourceDirectory, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel, string contentDescription, string singletonDescription, string collectionDescription); - static List GetDirectoryInfoCollection(Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string sourceDirectory, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel, string contentDescription, string singletonDescription, string collectionDescription) + List TestStatic_GetDirectoryInfoCollection(Configuration configuration, Model? model, PredictorModel? predictorModel, string sourceDirectory, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel, string contentDescription, string singletonDescription, string collectionDescription); + static List GetDirectoryInfoCollection(Configuration configuration, Model? model, PredictorModel? predictorModel, string sourceDirectory, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel, string contentDescription, string singletonDescription, string collectionDescription) => Result.GetDirectoryInfoCollection(configuration, model, predictorModel, sourceDirectory, description, outputResolution, includeResizeGroup, includeModel, includePredictorModel, contentDescription, singletonDescription, collectionDescription); } \ No newline at end of file diff --git a/Property/Models/Stateless/Result.cs b/Property/Models/Stateless/Result.cs index 3a8429c..335c1a9 100644 --- a/Property/Models/Stateless/Result.cs +++ b/Property/Models/Stateless/Result.cs @@ -5,13 +5,13 @@ namespace View_by_Distance.Property.Models.Stateless; internal class Result { - internal static string GetRelativePath(Models.Configuration configuration, string path) + internal static string GetRelativePath(Configuration configuration, string path) { - string result = XPath.GetRelativePath(path, configuration.RootDirectory.Length); + string result = Shared.Models.Stateless.Methods.IPath.GetRelativePath(path, configuration.RootDirectory.Length); return result; } - internal static string GetResultsGroupDirectory(Models.Configuration configuration, string description) + internal static string GetResultsGroupDirectory(Configuration configuration, string description) { string result = Path.Combine($"{configuration.RootDirectory} - Results", description.Replace("_", ") ")); if (!Directory.Exists(result)) @@ -19,7 +19,7 @@ internal class Result return result; } - internal static string GetResultsDateGroupDirectory(Models.Configuration configuration, string description) + internal static string GetResultsDateGroupDirectory(Configuration configuration, string description) { string result = Path.Combine(GetResultsGroupDirectory(configuration, description), configuration.DateGroup); if (!Directory.Exists(result)) @@ -27,7 +27,7 @@ internal class Result return result; } - internal static string GetResultsDateGroupDirectory(Models.Configuration configuration, string description, string jsonGroup) + internal static string GetResultsDateGroupDirectory(Configuration configuration, string description, string jsonGroup) { string result = Path.Combine(GetResultsDateGroupDirectory(configuration, description), jsonGroup); if (!Directory.Exists(result)) @@ -35,7 +35,7 @@ internal class Result return result; } - internal static string GetResultsFullGroupDirectory(Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel) + internal static string GetResultsFullGroupDirectory(Configuration configuration, Model? model, PredictorModel? predictorModel, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel) { string result = GetResultsDateGroupDirectory(configuration, description); if (includeResizeGroup) @@ -64,59 +64,69 @@ internal class Result return result; } - internal static List GetDirectoryInfoCollection(Models.Configuration configuration, string sourceDirectory, string dateGroupDirectory, string contentDescription, string singletonDescription, string collectionDescription, bool converted) + private static void CheckContent(string dateGroupDirectory, string contentDescription, string result) + { + string checkDirectory; + checkDirectory = Path.Combine(dateGroupDirectory, IResult.Content, IResult.AllInOne); + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + string contentDirectory = new(result.Replace("<>", IResult.Content)); + if (!Directory.Exists(contentDirectory)) + _ = Directory.CreateDirectory(contentDirectory); + checkDirectory = Path.Combine(dateGroupDirectory, string.Concat("() - ", contentDescription)); + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + } + + private static void CheckSingleton(string dateGroupDirectory, string singletonDescription, bool converted, string result) + { + string checkDirectory; + checkDirectory = Path.Combine(dateGroupDirectory, IResult.Singleton, IResult.AllInOne); + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + if (!converted) + { + string singletonDirectory = new(result.Replace("<>", IResult.Singleton)); + if (!Directory.Exists(singletonDirectory)) + _ = Directory.CreateDirectory(singletonDirectory); + } + checkDirectory = Path.Combine(dateGroupDirectory, string.Concat("{} - ", singletonDescription)); + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + } + + private static void CheckCollection(string dateGroupDirectory, string collectionDescription, bool converted, string result) + { + string checkDirectory = Path.Combine(dateGroupDirectory, IResult.Collection, IResult.AllInOne); + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + if (!converted) + { + string collectionDirectory = new(result.Replace("<>", IResult.Collection)); + if (!Directory.Exists(collectionDirectory)) + _ = Directory.CreateDirectory(collectionDirectory); + } + checkDirectory = Path.Combine(dateGroupDirectory, string.Concat("[] - ", collectionDescription)); + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + } + + internal static List GetDirectoryInfoCollection(Configuration configuration, string sourceDirectory, string dateGroupDirectory, string contentDescription, string singletonDescription, string collectionDescription, bool converted) { List results = new(); - string checkDirectory; string sourceDirectorySegment = GetRelativePath(configuration, sourceDirectory); string result = string.Concat(Path.Combine(dateGroupDirectory, "<>"), sourceDirectorySegment); if (!string.IsNullOrEmpty(contentDescription)) - { - checkDirectory = Path.Combine(dateGroupDirectory, IResult.Content, IResult.AllInOne); - if (!Directory.Exists(checkDirectory)) - _ = Directory.CreateDirectory(checkDirectory); - string contentDirectory = new(result.Replace("<>", IResult.Content)); - if (!Directory.Exists(contentDirectory)) - _ = Directory.CreateDirectory(contentDirectory); - checkDirectory = Path.Combine(dateGroupDirectory, string.Concat("() - ", contentDescription)); - if (!Directory.Exists(checkDirectory)) - _ = Directory.CreateDirectory(checkDirectory); - } + CheckContent(dateGroupDirectory, contentDescription, result); if (!string.IsNullOrEmpty(singletonDescription)) - { - checkDirectory = Path.Combine(dateGroupDirectory, IResult.Singleton, IResult.AllInOne); - if (!Directory.Exists(checkDirectory)) - _ = Directory.CreateDirectory(checkDirectory); - if (!converted) - { - string singletonDirectory = new(result.Replace("<>", IResult.Singleton)); - if (!Directory.Exists(singletonDirectory)) - _ = Directory.CreateDirectory(singletonDirectory); - } - checkDirectory = Path.Combine(dateGroupDirectory, string.Concat("{} - ", singletonDescription)); - if (!Directory.Exists(checkDirectory)) - _ = Directory.CreateDirectory(checkDirectory); - } + CheckSingleton(dateGroupDirectory, singletonDescription, converted, result); if (!string.IsNullOrEmpty(collectionDescription)) - { - checkDirectory = Path.Combine(dateGroupDirectory, IResult.Collection, IResult.AllInOne); - if (!Directory.Exists(checkDirectory)) - _ = Directory.CreateDirectory(checkDirectory); - if (!converted) - { - string collectionDirectory = new(result.Replace("<>", IResult.Collection)); - if (!Directory.Exists(collectionDirectory)) - _ = Directory.CreateDirectory(collectionDirectory); - } - checkDirectory = Path.Combine(dateGroupDirectory, string.Concat("[] - ", collectionDescription)); - if (!Directory.Exists(checkDirectory)) - _ = Directory.CreateDirectory(checkDirectory); - } + CheckCollection(dateGroupDirectory, collectionDescription, converted, result); results.Add(result); return results; } - internal static List GetDirectoryInfoCollection(Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string sourceDirectory, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel, string contentDescription, string singletonDescription, string collectionDescription) + internal static List GetDirectoryInfoCollection(Configuration configuration, Model? model, PredictorModel? predictorModel, string sourceDirectory, string description, string outputResolution, bool includeResizeGroup, bool includeModel, bool includePredictorModel, string contentDescription, string singletonDescription, string collectionDescription) { List results; bool converted = false; diff --git a/Property/Property.csproj b/Property/Property.csproj index 36837c5..7132761 100644 --- a/Property/Property.csproj +++ b/Property/Property.csproj @@ -10,7 +10,7 @@ Phares.View.by.Distance.Property false - 5.0.402.104 + 6.0.100.1 Mike Phares Phares true diff --git a/Resize/Models/_C_Resize.cs b/Resize/Models/_C_Resize.cs index e5337fa..4a436ad 100644 --- a/Resize/Models/_C_Resize.cs +++ b/Resize/Models/_C_Resize.cs @@ -6,7 +6,6 @@ using System.Runtime.InteropServices; using System.Text; using System.Text.Json; using View_by_Distance.Metadata.Models; -using View_by_Distance.Property.Models; using View_by_Distance.Shared.Models.Stateless; namespace View_by_Distance.Resize.Models; @@ -19,6 +18,9 @@ public class C_Resize public List AngleBracketCollection { get; } + protected readonly string _FilenameExtension; + public string FilenameExtension => _FilenameExtension; + private readonly Serilog.ILogger? _Log; private readonly int _TempResolutionWidth; private readonly int _TempResolutionHeight; @@ -35,7 +37,7 @@ public class C_Resize private readonly bool _ForceResizeLastWriteTimeToCreationTime; private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; - public C_Resize(bool forceResizeLastWriteTimeToCreationTime, bool overrideForResizeImages, bool propertiesChangedForResize, string[] validResolutions, ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters) + public C_Resize(bool forceResizeLastWriteTimeToCreationTime, bool overrideForResizeImages, bool propertiesChangedForResize, string[] validResolutions, ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) { _TempResolutionWidth = 3; _TempResolutionHeight = 4; @@ -46,6 +48,7 @@ public class C_Resize _ValidResolutions = validResolutions; _OutputResolutionOrientationIndex = 2; _EncoderParameters = encoderParameters; + _FilenameExtension = filenameExtension; _Log = Serilog.Log.ForContext(); AngleBracketCollection = new List(); _OverrideForResizeImages = overrideForResizeImages; @@ -66,14 +69,44 @@ public class C_Resize #pragma warning disable CA1416 - public static (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters) GetTuple(string outputExtension, int outputQuality) + public static (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) GetGifLowQuality() { - (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters) result; + (ImageCodecInfo, EncoderParameters, string) result; + System.Drawing.Imaging.ImageFormat imageFormat = System.Drawing.Imaging.ImageFormat.Gif; + ImageCodecInfo imageCodecInfo = (from l in ImageCodecInfo.GetImageEncoders() where l.FormatID == imageFormat.Guid select l).First(); + EncoderParameters encoderParameters = new(1); + encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 75L); + if (string.IsNullOrEmpty(imageCodecInfo.FilenameExtension)) + throw new NullReferenceException(nameof(imageCodecInfo.FilenameExtension)); + result = new(imageCodecInfo, encoderParameters, imageCodecInfo.FilenameExtension.Split(';')[0].ToLower()[1..]); + return result; + } + + public static (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) GetPngLowQuality() + { + (ImageCodecInfo, EncoderParameters, string) result; + System.Drawing.Imaging.ImageFormat imageFormat = System.Drawing.Imaging.ImageFormat.Png; + ImageCodecInfo imageCodecInfo = (from l in ImageCodecInfo.GetImageEncoders() where l.FormatID == imageFormat.Guid select l).First(); + EncoderParameters encoderParameters = new(1); + encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 75L); + if (string.IsNullOrEmpty(imageCodecInfo.FilenameExtension)) + throw new NullReferenceException(nameof(imageCodecInfo.FilenameExtension)); + result = new(imageCodecInfo, encoderParameters, imageCodecInfo.FilenameExtension.Split(';')[0].ToLower()[1..]); + return result; + } + + public static (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) GetTuple(string outputExtension, int outputQuality) + { + (ImageCodecInfo, EncoderParameters, string) result; System.Drawing.Imaging.ImageFormat imageFormat = outputExtension switch { ".gif" => System.Drawing.Imaging.ImageFormat.Gif, + ".jfif" => System.Drawing.Imaging.ImageFormat.Jpeg, + ".jpe" => System.Drawing.Imaging.ImageFormat.Jpeg, + ".jpeg" => System.Drawing.Imaging.ImageFormat.Jpeg, ".jpg" => System.Drawing.Imaging.ImageFormat.Jpeg, ".png" => System.Drawing.Imaging.ImageFormat.Png, + ".tif" => System.Drawing.Imaging.ImageFormat.Tiff, ".tiff" => System.Drawing.Imaging.ImageFormat.Tiff, _ => throw new Exception(), }; @@ -82,7 +115,9 @@ public class C_Resize // encoderParameters.Param[0] = New EncoderParameter(System.Drawing.Imaging.Encoder.Quality, CType(75L, Int32)) 'Default // encoderParameters.Param[0] = New EncoderParameter(System.Drawing.Imaging.Encoder.Quality, CType(95L, Int32)) 'Paint encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, outputQuality); - result = new(imageCodecInfo, encoderParameters); + if (string.IsNullOrEmpty(imageCodecInfo.FilenameExtension)) + throw new NullReferenceException(nameof(imageCodecInfo.FilenameExtension)); + result = new(imageCodecInfo, encoderParameters, imageCodecInfo.FilenameExtension.Split(';')[0].ToLower()[1..]); return result; } @@ -129,7 +164,7 @@ public class C_Resize } } - private byte[] SaveResizedSubfile3(string subFile, int[] resize, byte[] bytes, FileHolder? fileHolder) + private byte[] SaveResizedSubfile3(string subFile, int[] resize, byte[] bytes, Shared.Models.FileHolder? fileHolder) { byte[] results; Bitmap bitmap; @@ -181,7 +216,7 @@ public class C_Resize return results; } - private byte[] SaveResizedSubfile5(string subFile, int[] resize, byte[] bytes, FileHolder? fileHolder) + private byte[] SaveResizedSubfile5(string subFile, int[] resize, byte[] bytes, Shared.Models.FileHolder? fileHolder) { byte[] results; Bitmap bitmap; @@ -248,11 +283,11 @@ public class C_Resize #pragma warning restore CA1416 - private byte[] SaveResizedSubfile(string subFile, A_Property property, int[] resize, FileHolder? fileHolder) + private byte[] SaveResizedSubfile(string subFile, Shared.Models.Property property, int[] resize, Shared.Models.FileHolder? fileHolder) { byte[] results; - string dateTimeFormat = Property.Models.Stateless.A_Property.DateTimeFormat(); - DateTime dateTime = Property.Models.Stateless.A_Property.GetMinimumDateTime(property); + string dateTimeFormat = Shared.Models.Stateless.Methods.IProperty.DateTimeFormat(); + DateTime dateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(property); string dateTimeValue = dateTime.ToString(dateTimeFormat); byte[] bytes = _ASCIIEncoding.GetBytes(dateTimeValue); if (_ASCIIEncoding.GetString(bytes, 0, bytes.Length) != dateTimeValue) @@ -284,7 +319,7 @@ public class C_Resize return results; } - public byte[] GetResizedBytes(string outputResolution, string cResultsFullGroupDirectory, List> subFileTuples, Item item, A_Property property, Dictionary imageResizes) + public byte[] GetResizedBytes(string outputResolution, string cResultsFullGroupDirectory, List> subFileTuples, Shared.Models.Item item, Shared.Models.Property property, Dictionary imageResizes) { byte[] results; if (item.ImageFileHolder is null) @@ -300,7 +335,7 @@ public class C_Resize return results; } - public void SaveResizedSubfile(string outputResolution, string cResultsFullGroupDirectory, List> subFileTuples, Item item, string original, Dictionary imageResizes) + public void SaveResizedSubfile(string outputResolution, string cResultsFullGroupDirectory, List> subFileTuples, Shared.Models.Item item, string original, Dictionary imageResizes) { if (item.Property is null) throw new NullReferenceException(nameof(item.Property)); @@ -308,7 +343,7 @@ public class C_Resize throw new NullReferenceException(nameof(item.ImageFileHolder)); if (item.ResizedFileHolder is null) throw new NullReferenceException(nameof(item.ResizedFileHolder)); - FileHolder fileHolder = item.ResizedFileHolder; + Shared.Models.FileHolder fileHolder = item.ResizedFileHolder; if (!imageResizes.ContainsKey(outputResolution)) throw new Exception(); if (!fileHolder.Exists) @@ -320,7 +355,7 @@ public class C_Resize if (File.Exists(parentCheck)) { File.Move(parentCheck, fileInfo.FullName); - item.SetResizedFileHolder(FileHolder.Refresh(fileHolder)); + item.SetResizedFileHolder(_FilenameExtension, Shared.Models.Stateless.Methods.IFileHolder.Refresh(fileHolder)); } } int[] resize = imageResizes[outputResolution]; @@ -339,7 +374,7 @@ public class C_Resize else { bool check = false; - string[] changesFrom = new string[] { nameof(A_Property), nameof(B_Metadata), nameof(C_Resize) }; + string[] changesFrom = new string[] { nameof(Property.Models.A_Property), nameof(B_Metadata), nameof(C_Resize) }; List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); if (_OverrideForResizeImages) check = true; @@ -378,7 +413,7 @@ public class C_Resize return result; } - private Dictionary GetImageResizes(A_Property property, List> metadataCollection, string original) + private Dictionary GetImageResizes(Shared.Models.Property property, List> metadataCollection, string original) { Dictionary results = new(); int[] desired; @@ -424,7 +459,7 @@ public class C_Resize return results; } - public Dictionary GetResizeKeyValuePairs(string cResultsFullGroupDirectory, List> subFileTuples, List parseExceptions, string original, List> metadataCollection, Item item) + public Dictionary GetResizeKeyValuePairs(string cResultsFullGroupDirectory, List> subFileTuples, List parseExceptions, string original, List> metadataCollection, Shared.Models.Item item) { Dictionary results; if (item.Property?.Id is null) @@ -432,7 +467,7 @@ public class C_Resize if (item.ImageFileHolder is null) throw new NullReferenceException(nameof(item.ImageFileHolder)); string json; - string[] changesFrom = new string[] { nameof(A_Property), nameof(B_Metadata) }; + string[] changesFrom = new string[] { nameof(Property.Models.A_Property), nameof(B_Metadata) }; List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); string usingRelativePath = Path.Combine(AngleBracketCollection[0].Replace("<>", "{}"), string.Concat(item.ImageFileHolder.NameWithoutExtension, ".json")); string cResizeSingletonFile = Path.Combine(cResultsFullGroupDirectory, "{}", Property.Models.Stateless.IResult.AllInOne, $"{item.Property.Id.Value}{item.ImageFileHolder.ExtensionLowered}.json"); @@ -504,7 +539,7 @@ public class C_Resize json = JsonSerializer.Serialize(results, _WriteIndentedJsonSerializerOptions); bool updateDateWhenMatches = dateTimes.Any() && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime; DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max(); - if (Property.Models.Stateless.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime)) + if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime)) { if (!_ForceResizeLastWriteTimeToCreationTime && (!fileInfo.Exists || fileInfo.LastWriteTime == fileInfo.CreationTime)) subFileTuples.Add(new Tuple(nameof(C_Resize), DateTime.Now)); diff --git a/Resize/Resize.csproj b/Resize/Resize.csproj index 8a82d84..fb947ff 100644 --- a/Resize/Resize.csproj +++ b/Resize/Resize.csproj @@ -10,7 +10,7 @@ Phares.View.by.Distance.Resize false - 5.0.402.104 + 6.0.100.1 Mike Phares Phares true diff --git a/Shared/.vscode/format-report.json b/Shared/.vscode/format-report.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/Shared/.vscode/format-report.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/Property/Models/Closest.cs b/Shared/Models/Closest.cs similarity index 78% rename from Property/Models/Closest.cs rename to Shared/Models/Closest.cs index 67dc3f1..a4d603f 100644 --- a/Property/Models/Closest.cs +++ b/Shared/Models/Closest.cs @@ -1,14 +1,10 @@ +using System.Text.Json; using System.Text.Json.Serialization; -using View_by_Distance.Shared.Models; -namespace View_by_Distance.Property.Models; +namespace View_by_Distance.Shared.Models; -public class Closest +public class Closest : Properties.IClosest { - public const int MaximumPer = 50; - public const float MaximumMinimum = 0.50f; - public const bool SkipIsWrongYear = true; - public const float MinimumMinimum = 0.05f; protected readonly double? _Average; protected readonly int? _NormalizedPixelPercentage; @@ -36,14 +32,16 @@ public class Closest public Closest(int? normalizedPixelPercentage, DateTime minimumDateTime, bool? isWrongYear) : this(null, normalizedPixelPercentage, isWrongYear, null, minimumDateTime, null) - { - } + { } public Closest(int? normalizedPixelPercentage, DateTime minimumDateTime, bool? isWrongYear, PersonBirthday? personBirthday, List faceDistances) : this(faceDistances.Average(), normalizedPixelPercentage, isWrongYear, faceDistances.Min(), minimumDateTime, personBirthday) + { } + + public override string ToString() { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; } - public static Closest[] Get(List collection) => (from l in collection orderby l.Minimum < MinimumMinimum, l.Average select l).ToArray(); - } \ No newline at end of file diff --git a/Property/Models/Container.cs b/Shared/Models/Container.cs similarity index 70% rename from Property/Models/Container.cs rename to Shared/Models/Container.cs index 305d3fa..9426626 100644 --- a/Property/Models/Container.cs +++ b/Shared/Models/Container.cs @@ -1,8 +1,9 @@ +using System.Text.Json; using System.Text.Json.Serialization; -namespace View_by_Distance.Property.Models; +namespace View_by_Distance.Shared.Models; -public class Container +public class Container : Properties.IContainer { protected readonly int _G; @@ -31,4 +32,10 @@ public class Container _SourceDirectory = sourceDirectory; } + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + } \ No newline at end of file diff --git a/Shared/Models/DirectoryFileSystem.cs b/Shared/Models/DirectoryFileSystem.cs index ec0cc1a..ef92f46 100644 --- a/Shared/Models/DirectoryFileSystem.cs +++ b/Shared/Models/DirectoryFileSystem.cs @@ -1,10 +1,9 @@ using System.Text.Json; using System.Text.Json.Serialization; -using View_by_Distance.Shared.Models.Methods; namespace View_by_Distance.Shared.Models; -public class DirectoryFileSystem : FileSystem, Properties.IDirectoryFileSystem, IDirectoryFileSystem +public class DirectoryFileSystem : FileSystem, Properties.IDirectoryFileSystem { // protected new string _ClassName; diff --git a/Instance/Models/DistanceHolder.cs b/Shared/Models/DistanceHolder.cs similarity index 61% rename from Instance/Models/DistanceHolder.cs rename to Shared/Models/DistanceHolder.cs index 4555a9a..0de8aaf 100644 --- a/Instance/Models/DistanceHolder.cs +++ b/Shared/Models/DistanceHolder.cs @@ -1,38 +1,32 @@ using System.Text.Json; using System.Text.Json.Serialization; -using View_by_Distance.FaceRecognitionDotNet; -using View_by_Distance.Property.Models; -using View_by_Distance.Shared.Models.Properties; -namespace View_by_Distance.Instance.Models; +namespace View_by_Distance.Shared.Models; -internal class DistanceHolder +public class DistanceHolder : Properties.IDistanceHolder { - public IFace Face { init; get; } - public FaceEncoding? FaceEncoding { init; get; } + public Face Face { init; get; } public FileHolder FileHolder { init; get; } public int Id { init; get; } public string JSONDirectory { init; get; } - public ILocation Location { init; get; } + public Location? Location { init; get; } public string TSVDirectory { init; get; } public double Sort { get; set; } [JsonConstructor] public DistanceHolder( - IFace face, - FaceEncoding? faceEncoding, + Face face, FileHolder fileHolder, int id, string jsonDirectory, - ILocation location, + Location? location, string tsvDirectory ) { - FileHolder = fileHolder; + FileHolder = fileHolder; Sort = double.MaxValue; Face = face; - FaceEncoding = faceEncoding; Id = id; JSONDirectory = jsonDirectory; Location = location; @@ -45,4 +39,4 @@ internal class DistanceHolder return result; } -} +} \ No newline at end of file diff --git a/Shared/Models/Face.cs b/Shared/Models/Face.cs index d493a4b..30faf75 100644 --- a/Shared/Models/Face.cs +++ b/Shared/Models/Face.cs @@ -1,52 +1,68 @@ using System.Text.Json; using System.Text.Json.Serialization; -using View_by_Distance.Shared.Models.Methods; namespace View_by_Distance.Shared.Models; -public class Face : Properties.IFace, IFace +public class Face : Properties.IFace { - protected double? _Ī‘; protected DateTime _DateTime; - protected FaceEncoding _FaceEncoding; - protected Dictionary _FaceLandmarks; - protected OutputResolution _OutputResolution; - protected Location _Location; - protected int? _LocationIndex; - protected bool _Populated; - protected string _RelativePath; - public double? α => _Ī‘; + protected FaceEncoding? _FaceEncoding; + protected Dictionary? _FaceParts; + protected readonly OutputResolution? _OutputResolution; + protected Location? _Location; + protected readonly int? _LocationIndex; + protected readonly string _RelativePath; public DateTime DateTime => _DateTime; - public FaceEncoding FaceEncoding => _FaceEncoding; - public Dictionary FaceLandmarks => _FaceLandmarks; - public OutputResolution OutputResolution => _OutputResolution; - public Location Location => _Location; + public FaceEncoding? FaceEncoding => _FaceEncoding; + public Dictionary? FaceParts => _FaceParts; + public Location? Location => _Location; public int? LocationIndex => _LocationIndex; - public bool Populated => _Populated; + public OutputResolution? OutputResolution => _OutputResolution; public string RelativePath => _RelativePath; [JsonConstructor] - public Face(double? α, DateTime dateTime, FaceEncoding faceEncoding, Dictionary faceLandmarks, OutputResolution outputResolution, Location location, int? locationIndex, bool populated, string relativePath) + public Face(DateTime dateTime, FaceEncoding? faceEncoding, Dictionary? faceParts, Location? location, int? locationIndex, OutputResolution? outputResolution, string relativePath) { - _Ī‘ = α; _DateTime = dateTime; _FaceEncoding = faceEncoding; - _FaceLandmarks = faceLandmarks; + _FaceParts = faceParts; _Location = location; _LocationIndex = locationIndex; _OutputResolution = outputResolution; - _Populated = populated; _RelativePath = relativePath; } - double Stateless.Methods.IFace.TestStatic_Getα(int x1, int x2, int y1, int y2) => throw new NotImplementedException(); + public Face() : + this(DateTime.MinValue, null, null, null, null, null, string.Empty) + { } - string Stateless.Methods.IFace.TestStatic_GetJson(string jsonFileFullName) => throw new NotImplementedException(); + public Face(Location location) : + this(DateTime.MinValue, null, null, location, null, null, string.Empty) + { } - Face Stateless.Methods.IFace.TestStatic_GetFace(string jsonFileFullName) => throw new NotImplementedException(); + public Face(int facesCount, Face face) : + this(face.DateTime, face.FaceEncoding, face.FaceParts, face.Location, face.LocationIndex, face.OutputResolution, face.RelativePath) + { + if (face.Location?.Confidence is not null && face.OutputResolution is not null) + _Location = new(face.Location.Confidence, face.OutputResolution.Height, face.Location, face.OutputResolution.Width, facesCount); + } - Face[] Stateless.Methods.IFace.TestStatic_GetFaces(string jsonFileFullName) => throw new NotImplementedException(); + public Face(int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, Face face) : + this(face.DateTime, face.FaceEncoding, face.FaceParts, face.Location, face.LocationIndex, null, face.RelativePath) + { + if (outputResolutionHeight > 0) + _OutputResolution = new(outputResolutionHeight, outputResolutionOrientation, outputResolutionWidth); + } + + public Face(Property property, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation, string relativePath, int? i, Location? location) : + this(DateTime.MinValue, null, null, location, i, null, relativePath) + { + DateTime?[] dateTimes; + _OutputResolution = new(outputResolutionHeight, outputResolutionOrientation, outputResolutionWidth); + dateTimes = new DateTime?[] { property.CreationTime, property.LastWriteTime, property.DateTime, property.DateTimeDigitized, property.DateTimeOriginal, property.GPSDateStamp }; + _DateTime = (from l in dateTimes where l.HasValue select l.Value).Min(); + } public override string ToString() { @@ -54,4 +70,7 @@ public class Face : Properties.IFace, IFace return result; } + public void SetFaceEncoding(FaceEncoding faceEncoding) => _FaceEncoding = faceEncoding; + + public void SetFaceParts(Dictionary faceParts) => _FaceParts = faceParts; } \ No newline at end of file diff --git a/Shared/Models/FaceEncoding.cs b/Shared/Models/FaceEncoding.cs index 0afa974..482cfe2 100644 --- a/Shared/Models/FaceEncoding.cs +++ b/Shared/Models/FaceEncoding.cs @@ -1,10 +1,9 @@ using System.Text.Json; using System.Text.Json.Serialization; -using View_by_Distance.Shared.Models.Methods; namespace View_by_Distance.Shared.Models; -public class FaceEncoding : Properties.IFaceEncoding, IFaceEncoding +public class FaceEncoding : Properties.IFaceEncoding { protected double[] _RawEncoding; diff --git a/Shared/Models/FaceFileSystem.cs b/Shared/Models/FaceFileSystem.cs index 7851540..d313fe7 100644 --- a/Shared/Models/FaceFileSystem.cs +++ b/Shared/Models/FaceFileSystem.cs @@ -1,10 +1,9 @@ using System.Text.Json; using System.Text.Json.Serialization; -using View_by_Distance.Shared.Models.Methods; namespace View_by_Distance.Shared.Models; -public class FaceFileSystem : FileSystem, Properties.IFaceFileSystem, IFaceFileSystem +public class FaceFileSystem : FileSystem, Properties.IFaceFileSystem { // protected new string _ClassName; @@ -77,6 +76,38 @@ public class FaceFileSystem : FileSystem, Properties.IFaceFileSystem, IFaceFileS _SourceSize = sourceSize; } + private static void FileExists(Face face, int? faceBottom, int? faceRight, out int imageHeight, out int imageWidth, out long sourceSize, FileInfo fileInfo) + { + sourceSize = fileInfo.Length; + if (face.OutputResolution is not null) + { + imageWidth = face.OutputResolution.Width; + imageHeight = face.OutputResolution.Height; + } + else + { + System.Drawing.Size size = Stateless.Methods.ImageHelper.GetDimensions(fileInfo.FullName, faceRight, faceBottom); + imageWidth = size.Width; + imageHeight = size.Height; + } + } + + private static void FileDoesNotExist(string dataFullFileName, Face face, out int imageHeight, out int imageWidth, out long sourceSize, FileInfo fileInfo) + { + sourceSize = 0; + if (face.OutputResolution is null) + { + imageWidth = 0; + imageHeight = 0; + } + else + { + imageWidth = face.OutputResolution.Width; + imageHeight = face.OutputResolution.Height; + } + Stateless.Methods.IFaceFileSystem.SearchForMissingFile(fileInfo.FullName, fileInfo, dataFullFileName); + } + internal FaceFileSystem(string requestPath, int rootResultsDirectoryAbsoluteUriLength, string cResizeContent, string dFacesContentDirectory, string dataFullFileName, Face face) : base(string.Empty, string.Empty, dataFullFileName, string.Empty, DateTime.MinValue) { string confidence; @@ -130,38 +161,12 @@ public class FaceFileSystem : FileSystem, Properties.IFaceFileSystem, IFaceFileS string faceRelativePath = string.Concat(requestPath, new Uri(faceFullFileName).AbsoluteUri[rootResultsDirectoryAbsoluteUriLength..]); string sourceRelativePath = string.Concat(requestPath, new Uri(sourceFullFileName).AbsoluteUri[rootResultsDirectoryAbsoluteUriLength..]); FileInfo fileInfo = new(sourceFullFileName); - if (face.Populated && !File.Exists(faceFullFileName)) + if (face.FaceEncoding is not null && face.Location?.NormalizedPixelPercentage is not null && !File.Exists(faceFullFileName)) Stateless.Methods.IFaceFileSystem.SearchForMissingFile(faceFullFileName, fileInfo: new FileInfo(string.Empty), dataFullFileName); - if (!fileInfo.Exists) - { - sourceSize = 0; - if (face.OutputResolution is null) - { - imageWidth = 0; - imageHeight = 0; - } - else - { - imageWidth = face.OutputResolution.Width; - imageHeight = face.OutputResolution.Height; - } - Stateless.Methods.IFaceFileSystem.SearchForMissingFile(fileInfo.FullName, fileInfo, dataFullFileName); - } + if (fileInfo.Exists) + FileExists(face, faceBottom, faceRight, out imageHeight, out imageWidth, out sourceSize, fileInfo); else - { - sourceSize = fileInfo.Length; - if (face.OutputResolution is not null) - { - imageWidth = face.OutputResolution.Width; - imageHeight = face.OutputResolution.Height; - } - else - { - System.Drawing.Size size = Stateless.Methods.ImageHelper.GetDimensions(fileInfo.FullName, faceRight, faceBottom); - imageWidth = size.Width; - imageHeight = size.Height; - } - } + FileDoesNotExist(dataFullFileName, face, out imageHeight, out imageWidth, out sourceSize, fileInfo); _ClassName = "file"; _FaceBottom = faceBottom; _Confidence = confidence; @@ -176,7 +181,7 @@ public class FaceFileSystem : FileSystem, Properties.IFaceFileSystem, IFaceFileS _FaceLeft = faceLeft; _LocationDisplayIndex = locationDisplayIndex; _LocationIndex = face.LocationIndex; - _Populated = face.Populated; + _Populated = face.FaceEncoding is not null && face.Location?.NormalizedPixelPercentage is not null; _RelativePath = string.Empty; _FaceRight = faceRight; _SourceFullFileName = sourceFullFileName; @@ -187,13 +192,13 @@ public class FaceFileSystem : FileSystem, Properties.IFaceFileSystem, IFaceFileS _ImageWidth = imageWidth; } - string IFileSystem.GetDate() + public override string ToString() { - string result = _LastModified.ToString("MM/dd/yyyy hh:mm:ss tt"); + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); return result; } - string IFaceFileSystem.GetSize() + public string GetSize() { string result; if (_SourceSize is null) @@ -208,19 +213,9 @@ public class FaceFileSystem : FileSystem, Properties.IFaceFileSystem, IFaceFileS order++; len /= 1024; } - result = String.Format("{0:0.##} {1}", len, sizes[order]); + result = string.Format("{0:0.##} {1}", len, sizes[order]); } return result; } - void Stateless.Methods.IFaceFileSystem.TestStatic_SearchForMissingFile(string fullFileName, FileInfo fileInfo, string dataFullFileName) => throw new NotImplementedException(); - - FaceFileSystem[][] Stateless.Methods.IFaceFileSystem.TestStatic_GetFaceFileSystemCollection(string requestPath, string rootResultsDirectory, (string RootResultsDirectoryAbsoluteUri, string C_ResizeContentDirectory, string D_FacesContentDirectory, string E_DistanceCollectionDirectory) tuple, string selectedFileFullName) => throw new NotImplementedException(); - - public override string ToString() - { - string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); - return result; - } - } \ No newline at end of file diff --git a/Shared/Models/FacePoint.cs b/Shared/Models/FacePoint.cs index bfd5f2e..9bbbf48 100644 --- a/Shared/Models/FacePoint.cs +++ b/Shared/Models/FacePoint.cs @@ -1,11 +1,10 @@ using System.Drawing; using System.Text.Json; using System.Text.Json.Serialization; -using View_by_Distance.Shared.Models.Methods; namespace View_by_Distance.Shared.Models; -public class FacePoint : Properties.IFacePoint, IFacePoint +public class FacePoint : Properties.IFacePoint { protected int _Index; diff --git a/Property/Models/FileHolder.cs b/Shared/Models/FileHolder.cs similarity index 89% rename from Property/Models/FileHolder.cs rename to Shared/Models/FileHolder.cs index 4ef5257..38fe9ae 100644 --- a/Property/Models/FileHolder.cs +++ b/Shared/Models/FileHolder.cs @@ -1,7 +1,10 @@ -namespace View_by_Distance.Property.Models; +using System.Text.Json; -public class FileHolder +namespace View_by_Distance.Shared.Models; + +public class FileHolder : Properties.IFileHolder { + protected readonly DateTime _CreationTime; protected readonly string? _DirectoryName; protected readonly bool _Exists; @@ -65,6 +68,10 @@ public class FileHolder _NameWithoutExtension = Path.GetFileNameWithoutExtension(fileInfo.FullName); } - public static FileHolder Refresh(FileHolder fileHolder) => new(fileHolder.FullName); + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } } \ No newline at end of file diff --git a/Shared/Models/FileSystem.cs b/Shared/Models/FileSystem.cs index 4cd728c..9a2ef93 100644 --- a/Shared/Models/FileSystem.cs +++ b/Shared/Models/FileSystem.cs @@ -1,10 +1,9 @@ using System.Text.Json; using System.Text.Json.Serialization; -using View_by_Distance.Shared.Models.Methods; namespace View_by_Distance.Shared.Models; -public class FileSystem : Properties.IFileSystem, IFileSystem +public class FileSystem : Properties.IFileSystem { protected string _ClassName; @@ -37,14 +36,12 @@ public class FileSystem : Properties.IFileSystem, IFileSystem _LastModified = DateTime.Now; } - string IFileSystem.GetDate() + public string GetDate() { string result = _LastModified.ToString("MM/dd/yyyy hh:mm:ss tt"); return result; } - List Stateless.Methods.IFileSystem.TestStatic_GetFileSystemCollection(string requestPath, string rootResultsDirectory, (string RootResultsDirectoryAbsoluteUri, string C_ResizeContentDirectory, string D_FacesContentDirectory, string E_DistanceCollectionDirectory) tuple, string[] directories, string[] files, bool all) => throw new NotImplementedException(); - public override string ToString() { string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); diff --git a/Shared/Models/Item.cs b/Shared/Models/Item.cs new file mode 100644 index 0000000..1ad42b7 --- /dev/null +++ b/Shared/Models/Item.cs @@ -0,0 +1,95 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class Item : Properties.IItem +{ + + protected readonly bool? _Abandoned; + protected readonly bool? _Changed; + protected List _Closest; + protected List _Faces; + protected readonly FileHolder? _ImageFileHolder; + protected bool? _Moved; + protected List _Named; + protected readonly bool? _NoJson; + protected Property? _Property; + protected readonly string _RelativePath; + protected FileHolder? _ResizedFileHolder; + protected readonly string _SourceDirectoryFile; + protected bool _ValidImageFormatExtension; + public bool? Abandoned => _Abandoned; + public bool? Changed => _Changed; + public List Closest => _Closest; + public List Faces => _Faces; + public FileHolder? ImageFileHolder => _ImageFileHolder; + public bool? Moved => _Moved; + public bool? NoJson => _NoJson; + public List Named => _Named; + public Property? Property => _Property; + public string RelativePath => _RelativePath; + public FileHolder? ResizedFileHolder => _ResizedFileHolder; + public string SourceDirectoryFile => _SourceDirectoryFile; + public bool ValidImageFormatExtension => _ValidImageFormatExtension; + + [JsonConstructor] + public Item(bool? abandoned, bool? changed, List closest, List faces, FileHolder? imageFileHolder, bool? moved, List named, bool? noJson, Property? property, string relativePath, FileHolder? resizedFileHolder, string sourceDirectoryFile, bool validImageFormatExtension) + { + _Abandoned = abandoned; + _Changed = changed; + _Closest = closest; + _Faces = faces; + _ImageFileHolder = imageFileHolder; + _Moved = moved; + _Named = named; + _NoJson = noJson; + _Property = property; + _RelativePath = relativePath; + _ResizedFileHolder = resizedFileHolder; + _SourceDirectoryFile = sourceDirectoryFile; + _ValidImageFormatExtension = validImageFormatExtension; + } + + public Item(string sourceDirectoryFile, string relativePath, FileHolder? imageFileInfo, bool isValidImageFormatExtension, Property? property, bool? abandoned, bool? changed) + { + _Faces = new(); + _Named = new(); + _Closest = new(); + _Changed = changed; + _Property = property; + _Abandoned = abandoned; + _NoJson = abandoned is null; + _RelativePath = relativePath; + _ImageFileHolder = imageFileInfo; + _SourceDirectoryFile = sourceDirectoryFile; + _ValidImageFormatExtension = isValidImageFormatExtension; + if (relativePath.EndsWith(".json")) + throw new ArgumentException("Can not be a *.json file!"); + if (imageFileInfo is not null && imageFileInfo.ExtensionLowered is ".json") + throw new ArgumentException("Can not be a *.json file!"); + } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + + public void SetMoved(bool moved) => _Moved = moved; + + public void SetResizedFileHolder(string filenameExtension, FileHolder fileHolder) + { + if (fileHolder.ExtensionLowered == filenameExtension) + _ResizedFileHolder = fileHolder; + else if (fileHolder.ExtensionLowered.Length > 3 && fileHolder.ExtensionLowered[3] == 'e' && fileHolder.ExtensionLowered.Remove(3, 1) == filenameExtension) + _ResizedFileHolder = fileHolder; + else + throw new NotImplementedException(); + } + + public bool Any() => (_Abandoned.HasValue && _Abandoned.Value) || (_Changed.HasValue && _Changed.Value) || (_Moved.HasValue && _Moved.Value) || (_NoJson.HasValue && _NoJson.Value); + + public void Update(Property property) => _Property = property; + +} \ No newline at end of file diff --git a/Shared/Models/Location.cs b/Shared/Models/Location.cs index 1ea9b37..5cdafc6 100644 --- a/Shared/Models/Location.cs +++ b/Shared/Models/Location.cs @@ -1,10 +1,9 @@ using System.Text.Json; using System.Text.Json.Serialization; -using View_by_Distance.Shared.Models.Methods; namespace View_by_Distance.Shared.Models; -public class Location : Properties.ILocation, ILocation, IEquatable +public class Location : Properties.ILocation, IEquatable { protected int _Bottom; @@ -13,8 +12,8 @@ public class Location : Properties.ILocation, ILocation, IEquatable protected readonly int? _NormalizedPixelPercentage; protected int _Right; protected int _Top; - public int Bottom => _Bottom; public double Confidence => _Confidence; + public int Bottom => _Bottom; public int Left => _Left; public int? NormalizedPixelPercentage => _NormalizedPixelPercentage; public int Right => _Right; @@ -23,27 +22,22 @@ public class Location : Properties.ILocation, ILocation, IEquatable [JsonConstructor] public Location(int bottom, double confidence, int left, int? normalizedPixelPercentage, int right, int top) { - if (normalizedPixelPercentage < 0) - normalizedPixelPercentage = 3; _Confidence = confidence; _Bottom = bottom; _Left = left; _NormalizedPixelPercentage = normalizedPixelPercentage; _Right = right; _Top = top; + Check(bottom, left, normalizedPixelPercentage, right, top, zCount: 1); } - public Location(double confidence, int bottom, int left, int right, int top, int width, int height) : - this(bottom, confidence, left, GetNormalizedPixelPercentage(bottom, height, left, right, top, width), right, top) - { } + public Location(double confidence, int height, Location location, int width, int zCount) : + this(location.Bottom, confidence, location.Left, GetNormalizedPixelPercentage(location.Bottom, height, location.Left, location.Right, location.Top, width, zCount), location.Right, location.Top) => + Check(_Bottom, _Left, _NormalizedPixelPercentage, _Right, _Top, zCount); - public Location(double confidence, Location location, int width, int height) : - this(location.Bottom, confidence, location.Left, GetNormalizedPixelPercentage(location.Bottom, height, location.Left, location.Right, location.Top, width), location.Right, location.Top) - { } - - public Location(int left, int top, int right, int bottom, int width, int height) : - this(bottom, -1.0d, left, GetNormalizedPixelPercentage(bottom, height, left, right, top, width), right, top) - { } + public Location(int bottom, double confidence, int height, int left, int right, int top, int width, int zCount) : + this(bottom, confidence, left, GetNormalizedPixelPercentage(bottom, height, left, right, top, width, zCount), right, top) => + Check(_Bottom, height, _Left, _NormalizedPixelPercentage, _Right, _Top, width, zCount); public override bool Equals(object? obj) => Equals(obj as Location); @@ -53,6 +47,53 @@ public class Location : Properties.ILocation, ILocation, IEquatable return result; } + private static void Check(int bottom, int left, int right, int top, int zCount) + { + if (left < 0) + throw new Exception(); + if (right < 0) + throw new Exception(); + if (right < left) + throw new Exception(); + if (top < 0) + throw new Exception(); + if (bottom < 0) + throw new Exception(); + if (bottom < top) + throw new Exception(); + if (zCount < 0) + throw new Exception(); + } + + private static void Check(int bottom, int height, int left, int right, int top, int width, int zCount) + { + if (bottom > height) + throw new Exception(); + if (left > width) + throw new Exception(); + if (right > width) + throw new Exception(); + if (top > height) + throw new Exception(); + if (zCount < 0) + throw new Exception(); + } + + private static void Check(int bottom, int left, int? normalizedPixelPercentage, int right, int top, int zCount) + { + Check(bottom, left, right, top, zCount); + if (normalizedPixelPercentage.HasValue && normalizedPixelPercentage.Value < 0) + throw new Exception(); + } + + private static void Check(int bottom, int height, int left, int? normalizedPixelPercentage, int right, int top, int width, int zCount) + { + Check(bottom, left, right, top, zCount); + Check(bottom, height, left, right, top, width, zCount); + if (normalizedPixelPercentage.HasValue && normalizedPixelPercentage.Value < 0) + throw new Exception(); + } + public override int GetHashCode() { int hashCode = -773114317; @@ -63,16 +104,21 @@ public class Location : Properties.ILocation, ILocation, IEquatable return hashCode; } - public static int GetNormalizedPixelPercentage(int bottom, int height, int left, int right, int top, int width) + public static int GetNormalizedPixelPercentage(int bottom, int height, int left, int right, int top, int width, int zCount) { int result; double value; + int decimals = 6; + int factor = 1000000; + double total = width * height; + Check(bottom, left, right, top, zCount); double xCenter = left + ((right - left) / 2); double yCenter = top + ((bottom - top) / 2); - value = ((yCenter * width) + xCenter) / (width * height); + double at = ((yCenter - 1) * width) + xCenter; + value = at / total; if (value < 0) value = 3; - result = (int)(Math.Round((decimal)value, 4) * Stateless.Methods.ILocation.Factor); + result = (int)(Math.Round(value, decimals) * factor); return result; } diff --git a/Shared/Models/Methods/IClosest.cs b/Shared/Models/Methods/IClosest.cs new file mode 100644 index 0000000..e5c1c14 --- /dev/null +++ b/Shared/Models/Methods/IClosest.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IClosest : Stateless.Methods.IClosest +{ // ... + + // + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IContainer.cs b/Shared/Models/Methods/IContainer.cs new file mode 100644 index 0000000..3b7a13e --- /dev/null +++ b/Shared/Models/Methods/IContainer.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IContainer : Stateless.Methods.IContainer +{ // ... + + // + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IDistanceHolder.cs b/Shared/Models/Methods/IDistanceHolder.cs new file mode 100644 index 0000000..5540ed3 --- /dev/null +++ b/Shared/Models/Methods/IDistanceHolder.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IDistanceHolder : Stateless.Methods.IDistanceHolder +{ // ... + + // + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IFaceFileSystem.cs b/Shared/Models/Methods/IFaceFileSystem.cs index 768f34a..c49f4d1 100644 --- a/Shared/Models/Methods/IFaceFileSystem.cs +++ b/Shared/Models/Methods/IFaceFileSystem.cs @@ -1,8 +1,6 @@ namespace View_by_Distance.Shared.Models.Methods; -public interface IFaceFileSystem : Stateless.Methods.IFaceFileSystem, IFileSystem +public interface IFaceFileSystem : Stateless.Methods.IFaceFileSystem { - string GetSize(); - } \ No newline at end of file diff --git a/Shared/Models/Methods/IFacePoint.cs b/Shared/Models/Methods/IFacePoint.cs index 394b05e..3fd7d5a 100644 --- a/Shared/Models/Methods/IFacePoint.cs +++ b/Shared/Models/Methods/IFacePoint.cs @@ -1,6 +1,6 @@ namespace View_by_Distance.Shared.Models.Methods; -public interface IFacePoint +public interface IFacePoint : Stateless.Methods.IFacePoint { } \ No newline at end of file diff --git a/Shared/Models/Methods/IFileHolder.cs b/Shared/Models/Methods/IFileHolder.cs new file mode 100644 index 0000000..d76e192 --- /dev/null +++ b/Shared/Models/Methods/IFileHolder.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IFileHolder : Stateless.Methods.IFileHolder +{ // ... + + // + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IFileSystem.cs b/Shared/Models/Methods/IFileSystem.cs index a96115d..6a0d280 100644 --- a/Shared/Models/Methods/IFileSystem.cs +++ b/Shared/Models/Methods/IFileSystem.cs @@ -3,6 +3,4 @@ namespace View_by_Distance.Shared.Models.Methods; public interface IFileSystem : Stateless.Methods.IFileSystem { - string GetDate(); - } \ No newline at end of file diff --git a/Shared/Models/Methods/IItem.cs b/Shared/Models/Methods/IItem.cs new file mode 100644 index 0000000..570aba0 --- /dev/null +++ b/Shared/Models/Methods/IItem.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IItem : Stateless.Methods.IItem +{ // ... + + // + +} \ No newline at end of file diff --git a/Shared/Models/Methods/ILocation.cs b/Shared/Models/Methods/ILocation.cs index e637192..3c9d577 100644 --- a/Shared/Models/Methods/ILocation.cs +++ b/Shared/Models/Methods/ILocation.cs @@ -1,6 +1,6 @@ namespace View_by_Distance.Shared.Models.Methods; -public interface ILocation +public interface ILocation : Stateless.Methods.ILocation { } \ No newline at end of file diff --git a/Shared/Models/Methods/INamed.cs b/Shared/Models/Methods/INamed.cs new file mode 100644 index 0000000..8958a57 --- /dev/null +++ b/Shared/Models/Methods/INamed.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface INamed : Stateless.Methods.INamed +{ // ... + + // + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IOutputResolution.cs b/Shared/Models/Methods/IOutputResolution.cs index 2b7d3b9..3083443 100644 --- a/Shared/Models/Methods/IOutputResolution.cs +++ b/Shared/Models/Methods/IOutputResolution.cs @@ -1,6 +1,6 @@ namespace View_by_Distance.Shared.Models.Methods; -public interface IOutputResolution +public interface IOutputResolution : Stateless.Methods.IPerson { } \ No newline at end of file diff --git a/Shared/Models/Methods/IPath.cs b/Shared/Models/Methods/IPath.cs new file mode 100644 index 0000000..078f3fe --- /dev/null +++ b/Shared/Models/Methods/IPath.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Methods; + +public interface IPath : Stateless.Methods.IPath +{ // ... + + // + +} \ No newline at end of file diff --git a/Shared/Models/Methods/IProperty.cs b/Shared/Models/Methods/IProperty.cs index 4c88ca4..21cc6ea 100644 --- a/Shared/Models/Methods/IProperty.cs +++ b/Shared/Models/Methods/IProperty.cs @@ -1,6 +1,6 @@ namespace View_by_Distance.Shared.Models.Methods; -public interface IProperty +public interface IProperty : Stateless.Methods.IProperty { } \ No newline at end of file diff --git a/Shared/Models/Methods/IRelativePaths.cs b/Shared/Models/Methods/IRelativePaths.cs index a855ed8..bcfc817 100644 --- a/Shared/Models/Methods/IRelativePaths.cs +++ b/Shared/Models/Methods/IRelativePaths.cs @@ -1,6 +1,6 @@ namespace View_by_Distance.Shared.Models.Methods; -public interface IRelativePaths +public interface IRelativePaths : Stateless.Methods.IRelativePaths { } \ No newline at end of file diff --git a/Shared/Models/Named.cs b/Shared/Models/Named.cs new file mode 100644 index 0000000..d1f8f61 --- /dev/null +++ b/Shared/Models/Named.cs @@ -0,0 +1,37 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class Named : Properties.INamed +{ + + protected readonly bool? _IsWrongYear; + protected readonly DateTime _MinimumDateTime; + protected readonly int? _NormalizedPixelPercentage; + protected readonly PersonBirthday? _PersonBirthday; + public bool? IsWrongYear => _IsWrongYear; + public DateTime MinimumDateTime => _MinimumDateTime; + public int? NormalizedPixelPercentage => _NormalizedPixelPercentage; + public PersonBirthday? PersonBirthday => _PersonBirthday; + + [JsonConstructor] + public Named(bool? isWrongYear, DateTime minimumDateTime, int? normalizedPixelPercentage, PersonBirthday? personBirthday) + { + _IsWrongYear = isWrongYear; + _MinimumDateTime = minimumDateTime; + _NormalizedPixelPercentage = normalizedPixelPercentage; + _PersonBirthday = personBirthday; + } + + public Named(bool? isWrongYear, DateTime minimumDateTime, PersonBirthday? personBirthday) : + this(isWrongYear, minimumDateTime, null, personBirthday) + { } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Shared/Models/OutputResolution.cs b/Shared/Models/OutputResolution.cs index e88d8f2..cb4350a 100644 --- a/Shared/Models/OutputResolution.cs +++ b/Shared/Models/OutputResolution.cs @@ -1,10 +1,9 @@ using System.Text.Json; using System.Text.Json.Serialization; -using View_by_Distance.Shared.Models.Methods; namespace View_by_Distance.Shared.Models; -public class OutputResolution : Properties.IOutputResolution, IOutputResolution +public class OutputResolution : Properties.IOutputResolution { protected int _Height; diff --git a/Shared/Models/Properties/IClosest.cs b/Shared/Models/Properties/IClosest.cs new file mode 100644 index 0000000..eb52923 --- /dev/null +++ b/Shared/Models/Properties/IClosest.cs @@ -0,0 +1,13 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IClosest +{ + + public double? Average { get; } + public int? NormalizedPixelPercentage { get; } + public bool? IsWrongYear { get; } + public double? Minimum { get; } + public DateTime MinimumDateTime { get; } + public PersonBirthday? PersonBirthday { get; } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IConfiguration.cs b/Shared/Models/Properties/IConfiguration.cs deleted file mode 100644 index 2fa7554..0000000 --- a/Shared/Models/Properties/IConfiguration.cs +++ /dev/null @@ -1,45 +0,0 @@ -// using View_by_Distance.Shared.Models.Methods; - -// namespace View_by_Distance.Shared.Models.Properties; - -// public interface IConfiguration -// { - -// public bool? checkJsonForDistanceResults; -// public string[] loadOrCreateThenSaveDistanceResultsForOutputResolutions; -// public string[] loadOrCreateThenSaveImageFacesResultsForOutputResolutions; -// public bool? loadOrCreateThenSaveIndex; -// public bool? overrideForFaceImages; -// public bool? overrideForFaceLandmarkImages; -// public bool? overrideForResizeImages; -// public bool? propertiesChangedForDistance; -// public bool? propertiesChangedForFaces; -// public bool? propertiesChangedForIndex; -// public bool? propertiesChangedForMetadata; -// public bool? propertiesChangedForProperty; -// public bool? propertiesChangedForResize; -// public bool? reverse; -// public bool? saveFullYearOfRandomFiles; -// public bool? testDistanceResults; -// public int? distanceFactor; -// public int? locationConfidenceFactor; -// public int? mappedMaxIndex; -// public int? maxImagesInDirectoryForTopLevelFirstPass; -// public int? maxItemsInDistanceCollection; -// public int? numberOfJitters; -// public int? outputQuality; -// public int? paddingLoops; -// public string dateGroup; -// public string modelDirectory; -// public string modelName; -// public string outputExtension; -// public string predictorModelName; -// public string rootDirectory; -// public string[] ignoreExtensions; -// public string[] ignoreRelativePaths; -// public string[] mixedYearRelativePaths; -// public string[] outputResolutions; -// public string[] saveFaceLandmarkForOutputResolutions; -// public string[] validResolutions; - -// } \ No newline at end of file diff --git a/Shared/Models/Properties/IContainer.cs b/Shared/Models/Properties/IContainer.cs new file mode 100644 index 0000000..d9cc6f8 --- /dev/null +++ b/Shared/Models/Properties/IContainer.cs @@ -0,0 +1,11 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IContainer +{ + + public int G { get; } + public List Items { get; } + public int R { get; } + public string SourceDirectory { get; } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IDirectoryFileSystem.cs b/Shared/Models/Properties/IDirectoryFileSystem.cs index b2616d8..000c0d9 100644 --- a/Shared/Models/Properties/IDirectoryFileSystem.cs +++ b/Shared/Models/Properties/IDirectoryFileSystem.cs @@ -3,10 +3,4 @@ namespace View_by_Distance.Shared.Models.Properties; public interface IDirectoryFileSystem { - // protected new string ClassName { get; } - // protected new string DataDisplayFileName { get; } - // protected new string DataFullFileName { get; } - // protected new string Display { get; } - // protected new DateTime LastModified { get; } - } \ No newline at end of file diff --git a/Shared/Models/Properties/IDistanceHolder.cs b/Shared/Models/Properties/IDistanceHolder.cs new file mode 100644 index 0000000..7ce752f --- /dev/null +++ b/Shared/Models/Properties/IDistanceHolder.cs @@ -0,0 +1,14 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IDistanceHolder +{ + + public Face Face { init; get; } + public FileHolder FileHolder { init; get; } + public int Id { init; get; } + public string JSONDirectory { init; get; } + public Location? Location { init; get; } + public string TSVDirectory { init; get; } + public double Sort { get; set; } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IFace.cs b/Shared/Models/Properties/IFace.cs index b263c28..665fe7a 100644 --- a/Shared/Models/Properties/IFace.cs +++ b/Shared/Models/Properties/IFace.cs @@ -3,16 +3,12 @@ namespace View_by_Distance.Shared.Models.Properties; public interface IFace { -#pragma warning disable IDE1006 - public double? α { get; } -#pragma warning restore IDE1006 public DateTime DateTime { get; } - public FaceEncoding FaceEncoding { get; } - public Dictionary FaceLandmarks { get; } - public Location Location { get; } + public FaceEncoding? FaceEncoding { get; } + public Dictionary? FaceParts { get; } + public Location? Location { get; } public int? LocationIndex { get; } - public OutputResolution OutputResolution { get; } - public bool Populated { get; } + public OutputResolution? OutputResolution { get; } public string RelativePath { get; } } \ No newline at end of file diff --git a/Shared/Models/Properties/IFileHolder.cs b/Shared/Models/Properties/IFileHolder.cs new file mode 100644 index 0000000..f8f455f --- /dev/null +++ b/Shared/Models/Properties/IFileHolder.cs @@ -0,0 +1,16 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IFileHolder +{ + + public DateTime CreationTime { get; } + public string? DirectoryName { get; } + public bool Exists { get; } + public string ExtensionLowered { get; } + public string FullName { get; } + public DateTime LastWriteTime { get; } + public long? Length { get; } + public string Name { get; } + public string NameWithoutExtension { get; } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IItem.cs b/Shared/Models/Properties/IItem.cs new file mode 100644 index 0000000..ac6e519 --- /dev/null +++ b/Shared/Models/Properties/IItem.cs @@ -0,0 +1,20 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IItem +{ + + public bool? Abandoned { get; } + public bool? Changed { get; } + public List Closest { get; } + public List Faces { get; } + public FileHolder? ImageFileHolder { get; } + public bool? Moved { get; } + public bool? NoJson { get; } + public List Named { get; } + public Property? Property { get; } + public string RelativePath { get; } + public FileHolder? ResizedFileHolder { get; } + public string SourceDirectoryFile { get; } + public bool ValidImageFormatExtension { get; } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/INamed.cs b/Shared/Models/Properties/INamed.cs new file mode 100644 index 0000000..8494c63 --- /dev/null +++ b/Shared/Models/Properties/INamed.cs @@ -0,0 +1,11 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface INamed +{ + + public bool? IsWrongYear { get; } + public DateTime MinimumDateTime { get; } + public int? NormalizedPixelPercentage { get; } + public PersonBirthday? PersonBirthday { get; } + +} \ No newline at end of file diff --git a/Shared/Models/Properties/IPath.cs b/Shared/Models/Properties/IPath.cs new file mode 100644 index 0000000..5a69fd2 --- /dev/null +++ b/Shared/Models/Properties/IPath.cs @@ -0,0 +1,6 @@ +namespace View_by_Distance.Shared.Models.Properties; + +public interface IPath +{ + +} \ No newline at end of file diff --git a/Shared/Models/Property.cs b/Shared/Models/Property.cs index c3bd982..28f8304 100644 --- a/Shared/Models/Property.cs +++ b/Shared/Models/Property.cs @@ -6,61 +6,52 @@ namespace View_by_Distance.Shared.Models; public class Property : Properties.IProperty { - protected bool? _WrongYear; protected DateTime _CreationTime; - protected DateTime _LastWriteTime; protected DateTime? _DateTime; protected DateTime? _DateTimeDigitized; protected DateTime? _DateTimeOriginal; protected long _FileSize; protected DateTime? _GPSDateStamp; + protected int? _Height; protected int? _Id; protected int[] _Indices; - protected int? _Height; - protected int? _Width; + protected DateTime _LastWriteTime; protected string _Make; - protected int? _MetadataGroups; protected string _Model; protected string _Orientation; - protected string _UniqueImageId; - public bool? WrongYear => _WrongYear; + protected int? _Width; public DateTime CreationTime => _CreationTime; - public DateTime LastWriteTime => _LastWriteTime; public DateTime? DateTime => _DateTime; public DateTime? DateTimeDigitized => _DateTimeDigitized; public DateTime? DateTimeOriginal => _DateTimeOriginal; public long FileSize => _FileSize; public DateTime? GPSDateStamp => _GPSDateStamp; + public int? Height => _Height; public int? Id => _Id; public int[] Indices => _Indices; - public int? Height => _Height; - public int? Width => _Width; + public DateTime LastWriteTime => _LastWriteTime; public string Make => _Make; - public int? MetadataGroups => _MetadataGroups; public string Model => _Model; public string Orientation => _Orientation; - public string UniqueImageId => _UniqueImageId; + public int? Width => _Width; [JsonConstructor] - public Property(bool? wrongYear, DateTime creationTime, DateTime lastWriteTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeOriginal, DateTime? gpsDateStamp, long fileSize, int? id, int[] indices, int? height, int? width, string make, int? metadataGroups, string model, string orientation, string uniqueImageId) + public Property(DateTime creationTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeOriginal, long fileSize, DateTime? gpsDateStamp, int? height, int? id, int[] indices, DateTime lastWriteTime, string make, string model, string orientation, int? width) { _CreationTime = creationTime; _DateTime = dateTime; _DateTimeDigitized = dateTimeDigitized; _DateTimeOriginal = dateTimeOriginal; - _GPSDateStamp = gpsDateStamp; _FileSize = fileSize; + _GPSDateStamp = gpsDateStamp; _Height = height; _Id = id; _Indices = indices; _LastWriteTime = lastWriteTime; _Make = make; - _MetadataGroups = metadataGroups; _Model = model; _Orientation = orientation; _Width = width; - _WrongYear = wrongYear; - _UniqueImageId = uniqueImageId; } public override string ToString() @@ -69,4 +60,38 @@ public class Property : Properties.IProperty return result; } // ... + public List GetDateTimes() => Stateless.Methods.Property.GetDateTimes(_CreationTime, _LastWriteTime, _DateTime, _DateTimeDigitized, _DateTimeOriginal, _GPSDateStamp); + + public (bool?, string[]) IsWrongYear(string filteredSourceDirectoryFile, DateTime? minimumDateTime) + { + string[] results = Array.Empty(); + bool? result = null; + string year; + string directoryName; + string[] directorySegments; + string? check = Path.GetFullPath(filteredSourceDirectoryFile); + string? pathRoot = Path.GetPathRoot(filteredSourceDirectoryFile); + if (string.IsNullOrEmpty(pathRoot)) + throw new Exception(); + if (minimumDateTime.HasValue) + year = minimumDateTime.Value.ToString("yyyy"); + else + { + List dateTimes = GetDateTimes(); + year = dateTimes.Min().ToString("yyyy"); + } + for (int i = 0; i < int.MaxValue; i++) + { + check = Path.GetDirectoryName(check); + if (string.IsNullOrEmpty(check) || check == pathRoot) + break; + directoryName = Path.GetFileName(check); + directorySegments = directoryName.Split(' '); + (result, results) = Stateless.Methods.Property.IsWrongYear(directorySegments, year); + if (result.HasValue) + break; + } + return new(result, results); + } + } \ No newline at end of file diff --git a/Shared/Models/RelativePaths.cs b/Shared/Models/RelativePaths.cs index b1a3d41..aed577a 100644 --- a/Shared/Models/RelativePaths.cs +++ b/Shared/Models/RelativePaths.cs @@ -1,10 +1,9 @@ using System.Text.Json; using System.Text.Json.Serialization; -using View_by_Distance.Shared.Models.Methods; namespace View_by_Distance.Shared.Models; -public class RelativePaths : Properties.IRelativePaths, IRelativePaths +public class RelativePaths : Properties.IRelativePaths { protected string _Value; diff --git a/Shared/Models/Stateless/Methods/Closest.cs b/Shared/Models/Stateless/Methods/Closest.cs new file mode 100644 index 0000000..e918679 --- /dev/null +++ b/Shared/Models/Stateless/Methods/Closest.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class Closest +{ + + internal static Models.Closest[] Get(List collection) => (from l in collection orderby l.Minimum < IClosest.MinimumMinimum, l.Average select l).ToArray(); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/Container.cs b/Shared/Models/Stateless/Methods/Container.cs new file mode 100644 index 0000000..4cfd380 --- /dev/null +++ b/Shared/Models/Stateless/Methods/Container.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class Container +{ + + internal static double GetDefaultValue() => throw new Exception(); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/DistanceHolder.cs b/Shared/Models/Stateless/Methods/DistanceHolder.cs new file mode 100644 index 0000000..7e4b412 --- /dev/null +++ b/Shared/Models/Stateless/Methods/DistanceHolder.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class DistanceHolder +{ + + internal static double GetDefaultValue() => throw new Exception(); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/Face.cs b/Shared/Models/Stateless/Methods/Face.cs index caf2994..6958b7d 100644 --- a/Shared/Models/Stateless/Methods/Face.cs +++ b/Shared/Models/Stateless/Methods/Face.cs @@ -89,11 +89,40 @@ internal abstract class Face a = y2 - y1; double c = Math.Sqrt(Math.Pow(a, 2) + Math.Pow(b, 2)); if (y1 < y2) - result = (180 / Math.PI) * Math.Asin(a / c); + result = 180 / Math.PI * Math.Asin(a / c); else - result = (180 / Math.PI) * Math.Asin(a / c) * -1; + result = 180 / Math.PI * Math.Asin(a / c) * -1; } return result; } + internal static double? Getα(Dictionary faceParts) + { + double? result; + int? leftEyeX = null; + int? leftEyeY = null; + int? rightEyeX = null; + int? rightEyeY = null; + foreach ((FacePart facePart, Models.FacePoint[] facePoints) in faceParts) + { + if (facePart is not FacePart.LeftEye and not FacePart.RightEye) + continue; + if (facePart is FacePart.LeftEye) + { + leftEyeX = (int)(from l in facePoints select l.X).Average(); + leftEyeY = (int)(from l in facePoints select l.Y).Average(); + } + if (facePart is FacePart.RightEye) + { + rightEyeX = (int)(from l in facePoints select l.X).Average(); + rightEyeY = (int)(from l in facePoints select l.Y).Average(); + } + } + if (rightEyeX is null || leftEyeX is null || rightEyeY is null || leftEyeY is null) + result = null; + else + result = Getα(rightEyeX.Value, leftEyeX.Value, rightEyeY.Value, leftEyeY.Value); + return result; + } + } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/FacePoint.cs b/Shared/Models/Stateless/Methods/FacePoint.cs new file mode 100644 index 0000000..3bafee9 --- /dev/null +++ b/Shared/Models/Stateless/Methods/FacePoint.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class FacePoint +{ + + internal static double GetDefaultValue() => throw new Exception(); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/FileHolder.cs b/Shared/Models/Stateless/Methods/FileHolder.cs new file mode 100644 index 0000000..f68c80e --- /dev/null +++ b/Shared/Models/Stateless/Methods/FileHolder.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class FileHolder +{ + + internal static double GetDefaultValue() => throw new Exception(); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/FileSystem.cs b/Shared/Models/Stateless/Methods/FileSystem.cs index 569163c..8b35816 100644 --- a/Shared/Models/Stateless/Methods/FileSystem.cs +++ b/Shared/Models/Stateless/Methods/FileSystem.cs @@ -3,38 +3,54 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods; internal abstract class FileSystem { // ... + private static void SetFileSystemCollection(string requestPath, (string RootResultsDirectoryAbsoluteUri, string C_ResizeContentDirectory, string D_FacesContentDirectory, string E_DistanceCollectionDirectory) tuple, bool all, List results, IEnumerator subDirectoryFiles, List faceFileSystemCollection) + { + Models.Face face; + Models.FaceFileSystem faceFileSystem; + face = Face.GetFace(subDirectoryFiles.Current); + faceFileSystem = new Models.FaceFileSystem(requestPath, tuple.RootResultsDirectoryAbsoluteUri.Length, tuple.C_ResizeContentDirectory, tuple.D_FacesContentDirectory, subDirectoryFiles.Current, face); + if (!all) + results.Add(faceFileSystem); + else + faceFileSystemCollection.Add(faceFileSystem); + } + + private static void LoopFileSystemCollection(string requestPath, (string RootResultsDirectoryAbsoluteUri, string C_ResizeContentDirectory, string D_FacesContentDirectory, string E_DistanceCollectionDirectory) tuple, bool all, List results, IEnumerator subDirectoryFiles, List faceFileSystemCollection) + { + for (int j = 0; j < int.MaxValue; j++) + { + SetFileSystemCollection(requestPath, tuple, all, results, subDirectoryFiles, faceFileSystemCollection); + if (!all || !subDirectoryFiles.MoveNext()) + break; + } + } + + private static void SetFileSystemCollection(string[] directories, List results, int i) + { + DirectoryInfo directoryInfo = new(directories[i]); + Models.FileSystem fileSystem = new DirectoryFileSystem(directoryInfo); + results.Add(fileSystem); + } + + private static void LoopFileSystemCollection(string requestPath, (string RootResultsDirectoryAbsoluteUri, string C_ResizeContentDirectory, string D_FacesContentDirectory, string E_DistanceCollectionDirectory) tuple, string[] directories, bool all, List results, IEnumerator subDirectoryFiles, List faceFileSystemCollection, int i) + { + if (subDirectoryFiles.MoveNext()) + LoopFileSystemCollection(requestPath, tuple, all, results, subDirectoryFiles, faceFileSystemCollection); + else + SetFileSystemCollection(directories, results, i); + } + internal static List GetFileSystemCollection(string requestPath, (string RootResultsDirectoryAbsoluteUri, string C_ResizeContentDirectory, string D_FacesContentDirectory, string E_DistanceCollectionDirectory) tuple, string[] directories, string[] files, bool all) { List results = new(); Models.Face face; - DirectoryInfo directoryInfo; - Models.FileSystem fileSystem; Models.FaceFileSystem faceFileSystem; IEnumerator subDirectoryFiles; List faceFileSystemCollection = new(); for (int i = 0; i < directories.Length; i++) { subDirectoryFiles = Directory.EnumerateFiles(directories[i], "*.json", SearchOption.TopDirectoryOnly).GetEnumerator(); - if (!subDirectoryFiles.MoveNext()) - { - directoryInfo = new(directories[i]); - fileSystem = new DirectoryFileSystem(directoryInfo); - results.Add(fileSystem); - } - else - { - for (int j = 0; j < int.MaxValue; j++) - { - face = Face.GetFace(subDirectoryFiles.Current); - faceFileSystem = new Models.FaceFileSystem(requestPath, tuple.RootResultsDirectoryAbsoluteUri.Length, tuple.C_ResizeContentDirectory, tuple.D_FacesContentDirectory, subDirectoryFiles.Current, face); - if (!all) - results.Add(faceFileSystem); - else - faceFileSystemCollection.Add(faceFileSystem); - if (!all || !subDirectoryFiles.MoveNext()) - break; - } - } + LoopFileSystemCollection(requestPath, tuple, directories, all, results, subDirectoryFiles, faceFileSystemCollection, i); } for (int i = 0; i < files.Length; i++) { diff --git a/Shared/Models/Stateless/Methods/IClosest.cs b/Shared/Models/Stateless/Methods/IClosest.cs new file mode 100644 index 0000000..439400f --- /dev/null +++ b/Shared/Models/Stateless/Methods/IClosest.cs @@ -0,0 +1,15 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IClosest +{ // ... + + const int MaximumPer = 50; + const float MaximumMinimum = 0.50f; + const bool SkipIsWrongYear = true; + const float MinimumMinimum = 0.05f; + + Models.Closest[] TestStatic_Get(List collection); + + static Models.Closest[] Get(List collection) => Closest.Get(collection); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IContainer.cs b/Shared/Models/Stateless/Methods/IContainer.cs new file mode 100644 index 0000000..5cc804b --- /dev/null +++ b/Shared/Models/Stateless/Methods/IContainer.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IContainer +{ // ... + + double TestStatic_GetDefaultValue(); + + static double GetDefaultValue() => Container.GetDefaultValue(); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IDistanceHolder.cs b/Shared/Models/Stateless/Methods/IDistanceHolder.cs new file mode 100644 index 0000000..cd40393 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IDistanceHolder.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IDistanceHolder +{ // ... + + double TestStatic_GetDefaultValue(); + + static double GetDefaultValue() => DistanceHolder.GetDefaultValue(); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IFace.cs b/Shared/Models/Stateless/Methods/IFace.cs index 3ae7b75..50c115d 100644 --- a/Shared/Models/Stateless/Methods/IFace.cs +++ b/Shared/Models/Stateless/Methods/IFace.cs @@ -3,14 +3,22 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods; public interface IFace { // ... - double TestStatic_Getα(int x1, int x2, int y1, int y2); string TestStatic_GetJson(string jsonFileFullName); - Models.Face TestStatic_GetFace(string jsonFileFullName); - Models.Face[] TestStatic_GetFaces(string jsonFileFullName); - - static double Getα(int x1, int x2, int y1, int y2) => Face.Getα(x1, x2, y1, y2); static string GetJson(string jsonFileFullName) => Face.GetJson(jsonFileFullName); + + double TestStatic_Getα(int x1, int x2, int y1, int y2); + static double Getα(int x1, int x2, int y1, int y2) => Face.Getα(x1, x2, y1, y2); + + Models.Face TestStatic_GetFace(string jsonFileFullName); static Models.Face GetFace(string jsonFileFullName) => Face.GetFace(jsonFileFullName); + + Models.Face[] TestStatic_GetFaces(string jsonFileFullName); static Models.Face[] GetFaces(string jsonFileFullName) => Face.GetFaces(jsonFileFullName); + Models.Face[] TestStatic_Getα(Dictionary faceParts); + static double? Getα(Dictionary faceParts) => Face.Getα(faceParts); + + int?[] TestStatic_GetInts(List faces); + static int?[] GetInts(List faces) => (from l in faces where l.FaceEncoding is not null && l.Location?.NormalizedPixelPercentage is not null select l.Location?.NormalizedPixelPercentage).ToArray(); + } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IFacePoint.cs b/Shared/Models/Stateless/Methods/IFacePoint.cs new file mode 100644 index 0000000..7ef2889 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IFacePoint.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IFacePoint +{ // ... + + double TestStatic_GetDefaultValue(); + + static double GetDefaultValue() => FacePoint.GetDefaultValue(); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IFileHolder.cs b/Shared/Models/Stateless/Methods/IFileHolder.cs new file mode 100644 index 0000000..6537e08 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IFileHolder.cs @@ -0,0 +1,9 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IFileHolder +{ // ... + + Models.FileHolder TestStatic_Refresh(); + static Models.FileHolder Refresh(Models.FileHolder fileHolder) => new(fileHolder.FullName); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IItem.cs b/Shared/Models/Stateless/Methods/IItem.cs new file mode 100644 index 0000000..48503c5 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IItem.cs @@ -0,0 +1,9 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IItem +{ // ... + + string TestStatic_GetWrongYearFlag(bool? isWrongYear); + static string GetWrongYearFlag(bool? isWrongYear) => isWrongYear is null ? "#" : isWrongYear.Value ? "~" : "="; + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/ILocation.cs b/Shared/Models/Stateless/Methods/ILocation.cs index f4dfec0..f6fc9f5 100644 --- a/Shared/Models/Stateless/Methods/ILocation.cs +++ b/Shared/Models/Stateless/Methods/ILocation.cs @@ -3,6 +3,11 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods; public interface ILocation { // ... - public const int Factor = 10000; + Models.Location? TestStatic_GetLocation(Models.Location? location, int height, int width, int zCount); + static Models.Location? GetLocation(Models.Location? location, int height, int width, int zCount) => + location is null ? null : new(location.Confidence, height, location, width, zCount); + + int?[] TestStatic_GetInts(List locations); + static int?[] GetInts(List locations) => (from l in locations where l.NormalizedPixelPercentage is not null select l.NormalizedPixelPercentage).ToArray(); } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/INamed.cs b/Shared/Models/Stateless/Methods/INamed.cs new file mode 100644 index 0000000..5aa4652 --- /dev/null +++ b/Shared/Models/Stateless/Methods/INamed.cs @@ -0,0 +1,22 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface INamed +{ // ... + + double? TestStatic_GetReversedDeterministicHashCode(string fileName); + static double? GetReversedDeterministicHashCode(string fileName) => + Named.GetReversedDeterministicHashCode(fileName); + + double TestStatic_GetDeterministicHashCodeKey(Models.Item item, Models.Face face); + static double GetDeterministicHashCodeKey(Models.Item item, Models.Face face) => + Named.GetDeterministicHashCodeKey(item, face); + + double TestStatic_GetDeterministicHashCodeKey(Models.Item item, Models.Closest closest); + static double GetDeterministicHashCodeKey(Models.Item item, Models.Closest closest) => + Named.GetDeterministicHashCodeKey(item, closest); + + (string?, double?) TestStatic_GetReversedDeterministicHashCode(Dictionary> keyValuePairs, string file); + static (string?, double?) GetReversedDeterministicHashCode(Dictionary> keyValuePairs, string file) => + Named.GetReversedDeterministicHashCode(keyValuePairs, file); + +} \ No newline at end of file diff --git a/Property/Models/Stateless/IPath.cs b/Shared/Models/Stateless/Methods/IPath.cs similarity index 52% rename from Property/Models/Stateless/IPath.cs rename to Shared/Models/Stateless/Methods/IPath.cs index ef4f140..de90936 100644 --- a/Property/Models/Stateless/IPath.cs +++ b/Shared/Models/Stateless/Methods/IPath.cs @@ -1,24 +1,30 @@ -namespace View_by_Distance.Property.Models.Stateless; +namespace View_by_Distance.Shared.Models.Stateless.Methods; public interface IPath -{ +{ // ... string TestStatic_GetRelativePath(string path, int length); - static string GetRelativePath(string path, int length) => XPath.GetRelativePath(path, length); + static string GetRelativePath(string path, int length) + => XPath.GetRelativePath(path, length); bool TestStatic_DeleteEmptyDirectories(string rootDirectory); - static bool DeleteEmptyDirectories(string rootDirectory) => XPath.DeleteEmptyDirectories(rootDirectory); + static bool DeleteEmptyDirectories(string rootDirectory) + => XPath.DeleteEmptyDirectories(rootDirectory); List TestStatic_GetDirectoryNames(string directory); - static List GetDirectoryNames(string directory) => XPath.GetDirectoryNames(directory); + static List GetDirectoryNames(string directory) + => XPath.GetDirectoryNames(directory); bool TestStatic_WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite); - static bool WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches = null) => XPath.WriteAllText(path, contents, updateDateWhenMatches, compareBeforeWrite, updateToWhenMatches); + static bool WriteAllText(string path, string contents, bool updateDateWhenMatches, bool compareBeforeWrite, DateTime? updateToWhenMatches = null) + => XPath.WriteAllText(path, contents, updateDateWhenMatches, compareBeforeWrite, updateToWhenMatches); (int level, List directories) TestStatic_Get(string rootDirectory, string sourceDirectory); - static (int level, List directories) Get(string rootDirectory, string sourceDirectory) => XPath.Get(rootDirectory, sourceDirectory); + static (int level, List directories) Get(string rootDirectory, string sourceDirectory) + => XPath.Get(rootDirectory, sourceDirectory); string TestStatic_GetDirectory(string sourceDirectory, int level, string directoryName); - static string GetDirectory(string sourceDirectory, int level, string directoryName) => XPath.GetDirectory(sourceDirectory, level, directoryName); + static string GetDirectory(string sourceDirectory, int level, string directoryName) + => XPath.GetDirectory(sourceDirectory, level, directoryName); } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IProperty.cs b/Shared/Models/Stateless/Methods/IProperty.cs new file mode 100644 index 0000000..5c251f7 --- /dev/null +++ b/Shared/Models/Stateless/Methods/IProperty.cs @@ -0,0 +1,65 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IProperty +{ // ... + + string TestStatic_DateTimeFormat(); + static string DateTimeFormat() => "yyyy:MM:dd HH:mm:ss"; + + int TestStatic_GetDeterministicHashCode(byte[] value); + static int GetDeterministicHashCode(byte[] value) => + Property.GetDeterministicHashCode(value); + + int TestStatic_GetDeterministicHashCode(string value); + static int GetDeterministicHashCode(string value) => + Property.GetDeterministicHashCode(value); + + DateTime TestStatic_GetDateTime(Models.Property? property); + static DateTime GetDateTime(Models.Property? property) => + Property.GetDateTime(property); + + DateTime TestStatic_GetMinimumDateTime(Models.Property? property); + static DateTime GetMinimumDateTime(Models.Property? property) => + Property.GetMinimumDateTime(property); + + (int Season, string seasonName) TestStatic_GetSeason(int dayOfYear); + static (int Season, string seasonName) GetSeason(int dayOfYear) => + Property.GetSeason(dayOfYear); + + string TestStatic_GetDiffRootDirectory(string diffPropertyDirectory); + static string GetDiffRootDirectory(string diffPropertyDirectory) => + Property.GetDiffRootDirectory(diffPropertyDirectory); + + bool TestStatic_Any(List propertyHolderCollections); + static bool Any(List propertyHolderCollections) => + Property.Any(propertyHolderCollections); + + (bool?, string[]) TestStatic_IsWrongYear(string[] segments, string year); + static (bool?, string[]) IsWrongYear(string[] segments, string year) => + Property.IsWrongYear(segments, year); + + (bool?, string[]) TestStatic_IsWrongYear(string fileName, DateTime minimumDateTime); + static (bool?, string[]) IsWrongYear(string fileName, DateTime minimumDateTime) => + throw new NotImplementedException(); //Property.IsWrongYear(fileName, minimumDateTime); + + List TestStatic_GetDateTimes(Models.Property property); + static List GetDateTimes(Models.Property property) => + Property.GetDateTimes(property.CreationTime, property.LastWriteTime, property.DateTime, property.DateTimeDigitized, property.DateTimeOriginal, property.GPSDateStamp); + + double TestStatic_GetStandardDeviation(IEnumerable values, double average); + static double GetStandardDeviation(IEnumerable values, double average) => + Property.GetStandardDeviation(values, average); + + TimeSpan TestStatic_GetThreeStandardDeviationHigh(int minimum, Models.Container container); + static TimeSpan GetThreeStandardDeviationHigh(int minimum, Models.Container container) => + Property.GetThreeStandardDeviationHigh(minimum, container); + + (int, List, List) TestStatic_Get(Models.Container container, TimeSpan threeStandardDeviationHigh, int i); + static (int, List, List) Get(Models.Container container, TimeSpan threeStandardDeviationHigh, int i) => + Property.Get(container, threeStandardDeviationHigh, i); + + List TestStatic_GetDateTimes(DateTime creationTime, DateTime lastWriteTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeOriginal, DateTime? gpsDateStamp); + static List GetDateTimes(DateTime creationTime, DateTime lastWriteTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeOriginal, DateTime? gpsDateStamp) => + Property.GetDateTimes(creationTime, lastWriteTime, dateTime, dateTimeDigitized, dateTimeOriginal, gpsDateStamp); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/IRelativePaths.cs b/Shared/Models/Stateless/Methods/IRelativePaths.cs new file mode 100644 index 0000000..40bb8fa --- /dev/null +++ b/Shared/Models/Stateless/Methods/IRelativePaths.cs @@ -0,0 +1,10 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +public interface IRelativePaths +{ // ... + + double TestStatic_GetDefaultValue(); + + static double GetDefaultValue() => RelativePaths.GetDefaultValue(); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/ImageHelper.cs b/Shared/Models/Stateless/Methods/ImageHelper.cs index cb1033b..352248f 100644 --- a/Shared/Models/Stateless/Methods/ImageHelper.cs +++ b/Shared/Models/Stateless/Methods/ImageHelper.cs @@ -78,7 +78,7 @@ internal abstract class ImageHelper /// The path of the image to get the dimensions of. /// The dimensions of the specified image. /// The image was of an unrecognized format. - public static Size GetDimensions(BinaryReader binaryReader, int? faceRight, int? faceBottom) + internal static Size GetDimensions(BinaryReader binaryReader, int? faceRight, int? faceBottom) { Size? result = null; Dictionary> _ImageFormatDecoders = new() @@ -119,7 +119,7 @@ internal abstract class ImageHelper /// The path of the image to get the dimensions of. /// The dimensions of the specified image. /// The image was of an unrecognized format. - public static Size GetDimensions(string path, int? faceRight, int? faceBottom) + internal static Size GetDimensions(string path, int? faceRight, int? faceBottom) { Size result; using BinaryReader binaryReader = new(File.OpenRead(path)); diff --git a/Shared/Models/Stateless/Methods/Index.cs b/Shared/Models/Stateless/Methods/Index.cs index 88a44de..94befc5 100644 --- a/Shared/Models/Stateless/Methods/Index.cs +++ b/Shared/Models/Stateless/Methods/Index.cs @@ -3,6 +3,26 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods; internal abstract class Index { + private static string GetJsonContains(string result, string jsonFileFullName, FileInfo fileInfo, string fileSegmentCollection) + { + if (fileInfo is null) + fileInfo = new FileInfo(jsonFileFullName); + result = result.Replace(fileSegmentCollection, nameof(Properties.IIndex.RelativePaths)).Replace("\\\\", "/"); + File.WriteAllText(fileInfo.FullName, result); + File.SetLastWriteTime(fileInfo.FullName, fileInfo.LastWriteTime); + return result; + } + + private static string GetJsonSpecial(string result, string jsonFileFullName, FileInfo fileInfo) + { + if (fileInfo is null) + fileInfo = new FileInfo(jsonFileFullName); + result = result.Replace("/u0", "\\u0"); + File.WriteAllText(fileInfo.FullName, result); + File.SetLastWriteTime(fileInfo.FullName, fileInfo.LastWriteTime); + return result; + } + internal static string GetJson(string jsonFileFullName, FileInfo fileInfo) { string result; @@ -10,21 +30,9 @@ internal abstract class Index string fileSegmentCollection = "FileSegmentCollection"; result = File.ReadAllText(jsonFileFullName).Replace("Goolgle", "Google"); if (result.Contains(fileSegment) || result.Contains(fileSegmentCollection)) - { - if (fileInfo is null) - fileInfo = new FileInfo(jsonFileFullName); - result = result.Replace(fileSegmentCollection, nameof(Properties.IIndex.RelativePaths)).Replace("\\\\", "/"); - File.WriteAllText(fileInfo.FullName, result); - File.SetLastWriteTime(fileInfo.FullName, fileInfo.LastWriteTime); - } + result = GetJsonContains(result, jsonFileFullName, fileInfo, fileSegmentCollection); if (result.Contains("/u0")) - { - if (fileInfo is null) - fileInfo = new FileInfo(jsonFileFullName); - result = result.Replace("/u0", "\\u0"); - File.WriteAllText(fileInfo.FullName, result); - File.SetLastWriteTime(fileInfo.FullName, fileInfo.LastWriteTime); - } + result = GetJsonSpecial(result, jsonFileFullName, fileInfo); return result; } diff --git a/Shared/Models/Stateless/Methods/Item.cs b/Shared/Models/Stateless/Methods/Item.cs new file mode 100644 index 0000000..aacc8b1 --- /dev/null +++ b/Shared/Models/Stateless/Methods/Item.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class Item +{ + + internal static double GetDefaultValue() => throw new Exception(); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/Location.cs b/Shared/Models/Stateless/Methods/Location.cs new file mode 100644 index 0000000..67a1a7e --- /dev/null +++ b/Shared/Models/Stateless/Methods/Location.cs @@ -0,0 +1,6 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class Location +{ + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/Named.cs b/Shared/Models/Stateless/Methods/Named.cs new file mode 100644 index 0000000..83295b3 --- /dev/null +++ b/Shared/Models/Stateless/Methods/Named.cs @@ -0,0 +1,146 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class Named +{ + + private static double GetDeterministicHashCodeFileName(int id, int normalizedPixelPercentage) + => double.Parse($"{id}.{normalizedPixelPercentage}"); + + internal static double GetDeterministicHashCodeKey(Models.Item item, Models.Closest closest) + { + double result; + if (item.Property?.Id is null || item.ImageFileHolder is null || closest.NormalizedPixelPercentage is null) + throw new NullReferenceException(); + result = GetDeterministicHashCodeFileName(item.Property.Id.Value, closest.NormalizedPixelPercentage.Value); + return result; + } + + internal static double GetDeterministicHashCodeKey(Models.Item item, Models.Face face) + { + double result; + if (item.Property?.Id is null || item.ImageFileHolder is null || face.Location?.NormalizedPixelPercentage is null) + throw new NullReferenceException(); + result = GetDeterministicHashCodeFileName(item.Property.Id.Value, face.Location.NormalizedPixelPercentage.Value); + return result; + } + + private static double? GetReversedDeterministicHashCodeB(string fileName) + { + double? result; + string[] segments = fileName.Split('.'); + if (segments.Length < 2) + throw new Exception(); + string id = segments[0]; + string normalizedPixelPercentage = segments[1]; + if (!double.TryParse(string.Concat(id, '.', normalizedPixelPercentage), out double resultValue)) + result = null; + else + result = resultValue; + return result; + } + + internal static double? GetReversedDeterministicHashCode(string fileName) + { + double? result; + if (fileName.Length < 2 || fileName[1..].Contains('-')) + result = null; + else + result = GetReversedDeterministicHashCodeB(fileName); + return result; + } + + private static (string? check, int? normalizedPixelPercentage) GetReversedDeterministicHashCodeFromFace(string file, int idValue, int locationIndexValue, List faces) + { + string? check; + int? normalizedPixelPercentage; + Models.Face face = faces[locationIndexValue]; + if (face.Location?.NormalizedPixelPercentage is null) + { + check = null; + normalizedPixelPercentage = null; + } + else + { + string extensionLowered = Path.GetExtension(file).ToLower(); + normalizedPixelPercentage = face.Location.NormalizedPixelPercentage.Value; + double deterministicHashCodeKey = GetDeterministicHashCodeFileName(idValue, normalizedPixelPercentage.Value); + check = Path.Combine(string.Concat(Path.GetDirectoryName(file)), $"{deterministicHashCodeKey}{extensionLowered}"); + } + return (check, normalizedPixelPercentage); + } + + private static (string? check, int? normalizedPixelPercentage) GetReversedDeterministicHashCodeAfterParse(Dictionary> keyValuePairs, string file, int idValue, int locationIndexValue) + { + string? check; + int? normalizedPixelPercentage; + List faces = keyValuePairs[idValue]; + if (faces.Count > locationIndexValue) + (check, normalizedPixelPercentage) = GetReversedDeterministicHashCodeFromFace(file, idValue, locationIndexValue, faces); + else + { + check = null; + normalizedPixelPercentage = null; + } + return (check, normalizedPixelPercentage); + } + + private static (string? check, string id, int? normalizedPixelPercentage) GetReversedDeterministicHashCodeFromCollection(Dictionary> keyValuePairs, string file, string fileName) + { + string id; + string? check; + int? normalizedPixelPercentage; + string[] segments = fileName.Split(' '); + if (segments.Length < 3) + throw new Exception(); + id = segments[2].Split('.')[0]; + string locationIdex = segments[0]; + if (int.TryParse(id, out int idValue) && int.TryParse(locationIdex, out int locationIndexValue) && keyValuePairs.ContainsKey(idValue)) + (check, normalizedPixelPercentage) = GetReversedDeterministicHashCodeAfterParse(keyValuePairs, file, idValue, locationIndexValue); + else + { + check = null; + id = string.Empty; + normalizedPixelPercentage = null; + } + if (normalizedPixelPercentage is null) + id = string.Empty; + return new(check, id, normalizedPixelPercentage); + } + + private static (string?, double?) GetReversedDeterministicHashCode(Dictionary> keyValuePairs, string file, string fileName) + { + double? result; + string? check; + string id; + int? normalizedPixelPercentage; + if (keyValuePairs.Any()) + (check, id, normalizedPixelPercentage) = GetReversedDeterministicHashCodeFromCollection(keyValuePairs, file, fileName); + else + { + check = null; + id = string.Empty; + normalizedPixelPercentage = null; + } + if (normalizedPixelPercentage is null || !double.TryParse(string.Concat(id, '.', normalizedPixelPercentage.Value), out double resultValue)) + result = null; + else + result = resultValue; + return new(check, result); + } + + internal static (string?, double?) GetReversedDeterministicHashCode(Dictionary> keyValuePairs, string file) + { + double? result; + string? check; + string fileName = Path.GetFileName(file); + if (fileName.Contains('-')) + (check, result) = GetReversedDeterministicHashCode(keyValuePairs, file, fileName); + else + { + check = null; + result = null; + } + return new(check, result); + } + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/Person.cs b/Shared/Models/Stateless/Methods/Person.cs index d661bb4..4525465 100644 --- a/Shared/Models/Stateless/Methods/Person.cs +++ b/Shared/Models/Stateless/Methods/Person.cs @@ -48,12 +48,23 @@ internal abstract class Person return result; } + private static void SetSegments(ref string[] segments, string KeyFormat, ref DateTime incrementDate) + { + if (segments[0].Length != KeyFormat.Length || !segments[0].Contains('-') || !segments[0].Contains('_')) + { + List temporarySegments; + temporarySegments = segments.ToList(); + temporarySegments.Insert(0, incrementDate.ToString(KeyFormat)); + segments = temporarySegments.ToArray(); + incrementDate = incrementDate.AddDays(1); + } + } + internal static Dictionary Split(string knownPeopleFile) { Dictionary results = new(); string[] segments; DateTime personKey; - List temporarySegments; const string KeyFormat = "yyyy-MM-dd_HH"; DateTime incrementDate = new(1500, 1, 1); string[] lines = File.ReadAllLines(knownPeopleFile); @@ -66,13 +77,7 @@ internal abstract class Person segments = line.Replace(" //", "\t//").Split('\t'); if (segments.Length < 1) continue; - if (segments[0].Length != KeyFormat.Length || !segments[0].Contains('-') || !segments[0].Contains('_')) - { - temporarySegments = segments.ToList(); - temporarySegments.Insert(0, incrementDate.ToString(KeyFormat)); - segments = temporarySegments.ToArray(); - incrementDate = incrementDate.AddDays(1); - } + SetSegments(ref segments, KeyFormat, ref incrementDate); personKey = DateTime.ParseExact(segments[0], KeyFormat, cultureInfo); if (results.ContainsKey(personKey)) continue; @@ -88,7 +93,29 @@ internal abstract class Person return results.OrderBy(l => l.Key).ToDictionary(l => l.Key, l => l.Value); } - internal static Dictionary GetPersonCollection(string knownPeopleFile) + private static void SetValues(ref string name, ref string comment, ref string mergeName, KeyValuePair splitLine) + { + foreach (string segment in splitLine.Value) + { + if (!segment.Contains('*')) + continue; + mergeName = segment.Split('*')[1].Split('\t')[0]; + } + if (splitLine.Value[1].StartsWith("//")) + comment = splitLine.Value[1]; + else + name = splitLine.Value[1].Split('\t')[0]; + if (splitLine.Value.Length > 2) + comment = splitLine.Value[2]; + } + + private static void CheckSplitLineAndSetValues(ref string name, ref string comment, ref string mergeName, KeyValuePair splitLine) + { + if (splitLine.Value.Length > 1) + SetValues(ref name, ref comment, ref mergeName, splitLine); + } + + private static Dictionary GetPersonCollection(string knownPeopleFile) { Dictionary results = new(); string name; @@ -105,21 +132,7 @@ internal abstract class Person comment = string.Empty; oldName = string.Empty; mergeName = string.Empty; - if (splitLine.Value.Length > 1) - { - foreach (string segment in splitLine.Value) - { - if (!segment.Contains('*')) - continue; - mergeName = segment.Split('*')[1].Split('\t')[0]; - } - if (splitLine.Value[1].StartsWith("//")) - comment = splitLine.Value[1]; - else - name = splitLine.Value[1].Split('\t')[0]; - if (splitLine.Value.Length > 2) - comment = splitLine.Value[2]; - } + CheckSplitLineAndSetValues(ref name, ref comment, ref mergeName, splitLine); person = new(key, name, mergeName, oldName, comment); results.Add(splitLine.Key, person); } @@ -133,6 +146,19 @@ internal abstract class Person _ = IStorage.WriteAllText(fileName, json, updateDateWhenMatches: true, compareBeforeWrite: true); } + private static string GetComment(List urls, List comments, KeyValuePair keyValuePair) + { + string result = keyValuePair.Value.Comment[2..]; + if (!string.IsNullOrEmpty(result)) + { + if (result.StartsWith("http://") || result.StartsWith("https://")) + urls.Add(new(new(result))); + else + comments.Add(new(new(result))); + } + return result; + } + private static List GetPeopleFromText(Properties.IStorage storage, string localKnownPeopleFile) { List results = new(); @@ -156,16 +182,7 @@ internal abstract class Person if (name.First is null || string.IsNullOrEmpty(name.First.Value)) continue; if (!string.IsNullOrEmpty(keyValuePair.Value.Comment)) - { - comment = keyValuePair.Value.Comment[2..]; - if (!string.IsNullOrEmpty(comment)) - { - if (comment.StartsWith("http://") || comment.StartsWith("https://")) - urls.Add(new(new(comment))); - else - comments.Add(new(new(comment))); - } - } + comment = GetComment(urls, comments, keyValuePair); if (!string.IsNullOrEmpty(keyValuePair.Value.OldName)) comments.Add(new(new(keyValuePair.Value.OldName))); person = IPerson.CreatePerson(storage, birthday, name, comments, urls, numbers, emails, addresses); diff --git a/Property/Models/Stateless/A_Property.cs b/Shared/Models/Stateless/Methods/Property.cs similarity index 74% rename from Property/Models/Stateless/A_Property.cs rename to Shared/Models/Stateless/Methods/Property.cs index 15bfe64..771888c 100644 --- a/Property/Models/Stateless/A_Property.cs +++ b/Shared/Models/Stateless/Methods/Property.cs @@ -1,11 +1,9 @@ -namespace View_by_Distance.Property.Models.Stateless; +namespace View_by_Distance.Shared.Models.Stateless.Methods; -public static class A_Property +internal abstract class Property { - public static string DateTimeFormat() => "yyyy:MM:dd HH:mm:ss"; - - public static (int Season, string seasonName) GetSeason(int dayOfYear) + internal static (int Season, string seasonName) GetSeason(int dayOfYear) { (int Season, string seasonName) result = dayOfYear switch { @@ -18,19 +16,7 @@ public static class A_Property return result; } - public static List Get(Models.Configuration configuration, PropertyLogic propertyLogic) - { - List results; - long ticks = DateTime.Now.Ticks; - List exceptionsDirectories = new(); - results = Container.GetContainers(configuration, propertyLogic); - propertyLogic.ParallelWork(ticks, results, firstPass: false); - if (exceptionsDirectories.Any()) - throw new Exception(); - return results; - } - - public static int GetDeterministicHashCode(byte[] value) + internal static int GetDeterministicHashCode(byte[] value) { int result; unchecked @@ -49,7 +35,7 @@ public static class A_Property return result; } - public static int GetDeterministicHashCode(string value) + internal static int GetDeterministicHashCode(string value) { int result; unchecked @@ -68,7 +54,7 @@ public static class A_Property return result; } - public static (bool?, string[]) IsWrongYear(string[] segments, string year) + internal static (bool?, string[]) IsWrongYear(string[] segments, string year) { bool? result; string[] results = ( @@ -99,7 +85,7 @@ public static class A_Property return new(result, results); } - public static List GetDateTimes(DateTime creationTime, DateTime lastWriteTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeOriginal, DateTime? gpsDateStamp) + internal static List GetDateTimes(DateTime creationTime, DateTime lastWriteTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeOriginal, DateTime? gpsDateStamp) { List results = new() { @@ -117,7 +103,7 @@ public static class A_Property return results; } - public static DateTime GetDateTime(Models.A_Property? property) + internal static DateTime GetDateTime(Models.Property? property) { DateTime result; if (property is null) @@ -142,9 +128,7 @@ public static class A_Property return result; } - public static List GetDateTimes(Models.A_Property property) => GetDateTimes(property.CreationTime, property.LastWriteTime, property.DateTime, property.DateTimeDigitized, property.DateTimeOriginal, property.GPSDateStamp); - - public static DateTime GetMinimumDateTime(Models.A_Property? property) + internal static DateTime GetMinimumDateTime(Models.Property? property) { DateTime result; List dateTimes; @@ -152,13 +136,13 @@ public static class A_Property result = DateTime.MinValue; else { - dateTimes = GetDateTimes(property); + dateTimes = IProperty.GetDateTimes(property); result = dateTimes.Min(); } return result; } - public static string GetDiffRootDirectory(string diffPropertyDirectory) + internal static string GetDiffRootDirectory(string diffPropertyDirectory) { string result = string.Empty; string results = " - Results"; @@ -177,7 +161,7 @@ public static class A_Property return result; } - public static double GetStandardDeviation(IEnumerable values, double average) + internal static double GetStandardDeviation(IEnumerable values, double average) { double result = 0; if (!values.Any()) @@ -187,12 +171,23 @@ public static class A_Property return result; } - public static TimeSpan GetThreeStandardDeviationHigh(int minimum, Models.Container container) + private static long GetThreeStandardDeviationHigh(ref List ticksCollection, long min) + { + long result; + ticksCollection = (from l in ticksCollection select l - min).ToList(); + double sum = ticksCollection.Sum(); + double average = sum / ticksCollection.Count; + double standardDeviation = GetStandardDeviation(ticksCollection, average); + result = (long)Math.Ceiling(average + min + (standardDeviation * 3)); + return result; + } + + internal static TimeSpan GetThreeStandardDeviationHigh(int minimum, Models.Container container) { TimeSpan result; DateTime? minimumDateTime; List ticksCollection = new(); - foreach (Item item in container.Items) + foreach (Models.Item item in container.Items) { if (item.Property is null) continue; @@ -210,25 +205,19 @@ public static class A_Property if (ticksCollection.Count < minimum) threeStandardDeviationHigh = long.MaxValue; else - { - ticksCollection = (from l in ticksCollection select l - min).ToList(); - double sum = ticksCollection.Sum(); - double average = sum / ticksCollection.Count; - double standardDeviation = GetStandardDeviation(ticksCollection, average); - threeStandardDeviationHigh = (long)Math.Ceiling(average + min + (standardDeviation * 3)); - } + threeStandardDeviationHigh = GetThreeStandardDeviationHigh(ref ticksCollection, min); result = new TimeSpan(threeStandardDeviationHigh - min); return result; } - public static (int, List, List) Get(Models.Container container, TimeSpan threeStandardDeviationHigh, int i) + internal static (int, List, List) Get(Models.Container container, TimeSpan threeStandardDeviationHigh, int i) { - List results = new(); + List results = new(); int j = i; - Item item; long? ticks; - Item nextItem; + Models.Item item; TimeSpan timeSpan; + Models.Item nextItem; DateTime? minimumDateTime; DateTime? nextMinimumDateTime; List dateTimes = new(); @@ -264,7 +253,7 @@ public static class A_Property return new(j, dateTimes, results); } - public static bool Any(List propertyHolderCollections) + internal static bool Any(List propertyHolderCollections) { bool result = false; foreach (Models.Container container in propertyHolderCollections) diff --git a/Shared/Models/Stateless/Methods/RelativePaths.cs b/Shared/Models/Stateless/Methods/RelativePaths.cs new file mode 100644 index 0000000..3a792fd --- /dev/null +++ b/Shared/Models/Stateless/Methods/RelativePaths.cs @@ -0,0 +1,8 @@ +namespace View_by_Distance.Shared.Models.Stateless.Methods; + +internal abstract class RelativePaths +{ + + internal static double GetDefaultValue() => throw new Exception(); + +} \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/WorkingDirectory.cs b/Shared/Models/Stateless/Methods/WorkingDirectory.cs index 95a85fa..50580c9 100644 --- a/Shared/Models/Stateless/Methods/WorkingDirectory.cs +++ b/Shared/Models/Stateless/Methods/WorkingDirectory.cs @@ -12,11 +12,11 @@ internal abstract class WorkingDirectory List directories = new(); Environment.SpecialFolder[] specialFolders = new Environment.SpecialFolder[] { - Environment.SpecialFolder.LocalApplicationData, - Environment.SpecialFolder.ApplicationData, - Environment.SpecialFolder.History, - Environment.SpecialFolder.CommonApplicationData, - Environment.SpecialFolder.InternetCache + Environment.SpecialFolder.LocalApplicationData, + Environment.SpecialFolder.ApplicationData, + Environment.SpecialFolder.History, + Environment.SpecialFolder.CommonApplicationData, + Environment.SpecialFolder.InternetCache }; foreach (Environment.SpecialFolder specialFolder in specialFolders) directories.Add(Path.Combine(Environment.GetFolderPath(specialFolder), subDirectoryName, executingAssemblyName)); diff --git a/Property/Models/Stateless/Path.cs b/Shared/Models/Stateless/Methods/XPath.cs similarity index 98% rename from Property/Models/Stateless/Path.cs rename to Shared/Models/Stateless/Methods/XPath.cs index 08fffb3..594be2c 100644 --- a/Property/Models/Stateless/Path.cs +++ b/Shared/Models/Stateless/Methods/XPath.cs @@ -1,6 +1,6 @@ -namespace View_by_Distance.Property.Models.Stateless; +namespace View_by_Distance.Shared.Models.Stateless.Methods; -internal class XPath +internal abstract class XPath { internal static string GetRelativePath(string path, int length) diff --git a/Shared/Models/XPath.cs b/Shared/Models/XPath.cs new file mode 100644 index 0000000..51a737a --- /dev/null +++ b/Shared/Models/XPath.cs @@ -0,0 +1,14 @@ +using System.Text.Json; + +namespace View_by_Distance.Shared.Models; + +public class XPath : Properties.IPath +{ + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); + return result; + } + +} \ No newline at end of file diff --git a/Shared/Phares/Shared/IsEnvironment.cs b/Shared/Phares/Shared/IsEnvironment.cs index f5f24a9..44ad491 100644 --- a/Shared/Phares/Shared/IsEnvironment.cs +++ b/Shared/Phares/Shared/IsEnvironment.cs @@ -35,9 +35,9 @@ public class IsEnvironment if (testCategory.EndsWith(".json")) { Production = testCategory == "appsettings.json"; - Staging = testCategory.EndsWith(nameof(Staging)); + Staging = testCategory.Contains(nameof(Staging)); OSX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); - Development = testCategory.EndsWith(nameof(Development)); + Development = testCategory.Contains(nameof(Development)); Linux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); DebuggerWasAttachedDuringConstructor = Debugger.IsAttached; Windows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); diff --git a/Shared/View-by-Distance.Shared.csproj b/Shared/View-by-Distance.Shared.csproj index 0f827ef..4043237 100644 --- a/Shared/View-by-Distance.Shared.csproj +++ b/Shared/View-by-Distance.Shared.csproj @@ -9,7 +9,7 @@ Phares.View.by.Distance.Shared false - 5.0.402.104 + 6.0.100.1 Mike Phares Phares true diff --git a/Tests/Models/Binder/Configuration.cs b/Tests/Models/Binder/Configuration.cs index 9c890ba..af47e75 100644 --- a/Tests/Models/Binder/Configuration.cs +++ b/Tests/Models/Binder/Configuration.cs @@ -1,3 +1,5 @@ +using Microsoft.Extensions.Configuration; +using Phares.Shared; using System.ComponentModel.DataAnnotations; using System.Text.Json; @@ -6,9 +8,12 @@ namespace View_by_Distance.Tests.Models.Binder; public class Configuration { +#nullable disable + [Display(Name = "Check Json For Distance Results"), Required] public bool? CheckJsonForDistanceResults { get; set; } [Display(Name = "CrossDirectory Max Items In Distance Collection"), Required] public int? CrossDirectoryMaxItemsInDistanceCollection { get; set; } [Display(Name = "Distance Factor"), Required] public int? DistanceFactor { get; set; } + [Display(Name = "Force Face Last Write Time to Creation Time"), Required] public bool? ForceFaceLastWriteTimeToCreationTime { get; set; } [Display(Name = "Force Metadata Last Write Time to Creation Time"), Required] public bool? ForceMetadataLastWriteTimeToCreationTime { get; set; } [Display(Name = "Force Resize Last Write Time to Creation Time"), Required] public bool? ForceResizeLastWriteTimeToCreationTime { get; set; } [Display(Name = "Ignore Extensions"), Required] public string[] IgnoreExtensions { get; set; } @@ -39,7 +44,7 @@ public class Configuration [Display(Name = "Properties Changed For Index"), Required] public bool? PropertiesChangedForIndex { get; set; } [Display(Name = "Properties Changed For Metadata"), Required] public bool? PropertiesChangedForMetadata { get; set; } [Display(Name = "Properties Changed For Resize"), Required] public bool? PropertiesChangedForResize { get; set; } - [Display(Name = "Property Configuration"), Required] public Property.Models.Configuration? PropertyConfiguration { get; set; } + [Display(Name = "Property Configuration"), Required] public Property.Models.Configuration PropertyConfiguration { get; set; } [Display(Name = "Reverse"), Required] public bool? Reverse { get; set; } [Display(Name = "Save Face Landmark For Output Resolutions"), Required] public string[] SaveFaceLandmarkForOutputResolutions { get; set; } [Display(Name = "Save Full Year Of Random Files"), Required] public bool? SaveFullYearOfRandomFiles { get; set; } @@ -49,50 +54,7 @@ public class Configuration [Display(Name = "Test Distance Results"), Required] public bool? TestDistanceResults { get; set; } [Display(Name = "Valid Resolutions"), Required] public string[] ValidResolutions { get; set; } - public Configuration() - { - CheckJsonForDistanceResults = null; - CrossDirectoryMaxItemsInDistanceCollection = null; - DistanceFactor = null; - ForceMetadataLastWriteTimeToCreationTime = null; - ForceResizeLastWriteTimeToCreationTime = null; - IgnoreExtensions = Array.Empty(); - IgnoreRelativePaths = Array.Empty(); - JuliePhares = Array.Empty(); - LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions = Array.Empty(); - LoadOrCreateThenSaveDistanceResultsForOutputResolutions = Array.Empty(); - LoadOrCreateThenSaveImageFacesResultsForOutputResolutions = Array.Empty(); - LoadOrCreateThenSaveIndex = null; - LocationConfidenceFactor = null; - MappedMaxIndex = null; - MaxItemsInDistanceCollection = null; - MixedYearRelativePaths = Array.Empty(); - ModelDirectory = string.Empty; - ModelName = string.Empty; - NumberOfJitters = null; - NumberOfTimesToUpsample = null; - OutputExtension = string.Empty; - OutputQuality = null; - OutputResolutions = Array.Empty(); - OverrideForFaceImages = null; - OverrideForFaceLandmarkImages = null; - OverrideForResizeImages = null; - PaddingLoops = null; - PredictorModelName = string.Empty; - PropertiesChangedForDistance = null; - PropertiesChangedForFaces = null; - PropertiesChangedForIndex = null; - PropertiesChangedForMetadata = null; - PropertiesChangedForResize = null; - Reverse = null; - SaveFaceLandmarkForOutputResolutions = Array.Empty(); - SaveFullYearOfRandomFiles = null; - SaveResizedSubfiles = null; - SaveShortcutsForOutputResolutions = Array.Empty(); - SkipSearch = null; - TestDistanceResults = null; - ValidResolutions = Array.Empty(); - } +#nullable restore public override string ToString() { @@ -100,4 +62,146 @@ public class Configuration return result; } + private static Models.Configuration Get(Configuration configuration) + { + Models.Configuration result; + if (configuration.CheckJsonForDistanceResults is null) + throw new NullReferenceException(nameof(configuration.CheckJsonForDistanceResults)); + if (configuration.CrossDirectoryMaxItemsInDistanceCollection is null) + throw new NullReferenceException(nameof(configuration.CrossDirectoryMaxItemsInDistanceCollection)); + if (configuration.DistanceFactor is null) + throw new NullReferenceException(nameof(configuration.DistanceFactor)); + if (configuration.ForceFaceLastWriteTimeToCreationTime is null) + throw new NullReferenceException(nameof(configuration.ForceFaceLastWriteTimeToCreationTime)); + if (configuration.ForceMetadataLastWriteTimeToCreationTime is null) + throw new NullReferenceException(nameof(configuration.ForceMetadataLastWriteTimeToCreationTime)); + if (configuration.ForceResizeLastWriteTimeToCreationTime is null) + throw new NullReferenceException(nameof(configuration.ForceResizeLastWriteTimeToCreationTime)); + if (configuration.IgnoreExtensions is null) + throw new NullReferenceException(nameof(configuration.IgnoreExtensions)); + if (configuration.IgnoreRelativePaths is null) + throw new NullReferenceException(nameof(configuration.IgnoreRelativePaths)); + if (configuration.LoadOrCreateThenSaveIndex is null) + throw new NullReferenceException(nameof(configuration.LoadOrCreateThenSaveIndex)); + if (configuration.LocationConfidenceFactor is null) + throw new NullReferenceException(nameof(configuration.LocationConfidenceFactor)); + if (configuration.MaxItemsInDistanceCollection is null) + throw new NullReferenceException(nameof(configuration.MaxItemsInDistanceCollection)); + if (configuration.MixedYearRelativePaths is null) + throw new NullReferenceException(nameof(configuration.MixedYearRelativePaths)); + if (configuration.NumberOfJitters is null) + throw new NullReferenceException(nameof(configuration.NumberOfJitters)); + if (configuration.NumberOfTimesToUpsample is null) + throw new NullReferenceException(nameof(configuration.NumberOfTimesToUpsample)); + if (configuration.OutputQuality is null) + throw new NullReferenceException(nameof(configuration.OutputQuality)); + if (configuration.OutputResolutions is null) + throw new NullReferenceException(nameof(configuration.OutputResolutions)); + if (configuration.OverrideForFaceImages is null) + throw new NullReferenceException(nameof(configuration.OverrideForFaceImages)); + if (configuration.OverrideForFaceLandmarkImages is null) + throw new NullReferenceException(nameof(configuration.OverrideForFaceLandmarkImages)); + if (configuration.OverrideForResizeImages is null) + throw new NullReferenceException(nameof(configuration.OverrideForResizeImages)); + if (configuration.PaddingLoops is null) + throw new NullReferenceException(nameof(configuration.PaddingLoops)); + if (configuration.PropertiesChangedForDistance is null) + throw new NullReferenceException(nameof(configuration.PropertiesChangedForDistance)); + if (configuration.PropertiesChangedForFaces is null) + throw new NullReferenceException(nameof(configuration.PropertiesChangedForFaces)); + if (configuration.PropertiesChangedForIndex is null) + throw new NullReferenceException(nameof(configuration.PropertiesChangedForIndex)); + if (configuration.PropertiesChangedForMetadata is null) + throw new NullReferenceException(nameof(configuration.PropertiesChangedForMetadata)); + if (configuration.PropertiesChangedForResize is null) + throw new NullReferenceException(nameof(configuration.PropertiesChangedForResize)); + if (configuration.Reverse is null) + throw new NullReferenceException(nameof(configuration.Reverse)); + if (configuration.SaveFaceLandmarkForOutputResolutions is null) + throw new NullReferenceException(nameof(configuration.SaveFaceLandmarkForOutputResolutions)); + if (configuration.SaveFullYearOfRandomFiles is null) + throw new NullReferenceException(nameof(configuration.SaveFullYearOfRandomFiles)); + if (configuration.SaveResizedSubfiles is null) + throw new NullReferenceException(nameof(configuration.SaveResizedSubfiles)); + if (configuration.SkipSearch is null) + throw new NullReferenceException(nameof(configuration.SkipSearch)); + if (configuration.TestDistanceResults is null) + throw new NullReferenceException(nameof(configuration.TestDistanceResults)); + if (configuration.ValidResolutions is null) + throw new NullReferenceException(nameof(configuration.ValidResolutions)); + if (configuration.LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions is null) + configuration.LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions = Array.Empty(); + if (configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions is null) + configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions = Array.Empty(); + if (configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions is null) + configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions = Array.Empty(); + if (configuration.SaveFaceLandmarkForOutputResolutions is null) + configuration.SaveFaceLandmarkForOutputResolutions = Array.Empty(); + if (configuration.SaveShortcutsForOutputResolutions is null) + configuration.SaveShortcutsForOutputResolutions = Array.Empty(); + result = new(configuration.PropertyConfiguration, + configuration.CheckJsonForDistanceResults.Value, + configuration.CrossDirectoryMaxItemsInDistanceCollection.Value, + configuration.DistanceFactor.Value, + configuration.ForceFaceLastWriteTimeToCreationTime.Value, + configuration.ForceMetadataLastWriteTimeToCreationTime.Value, + configuration.ForceResizeLastWriteTimeToCreationTime.Value, + configuration.IgnoreExtensions, + configuration.IgnoreRelativePaths, + configuration.JuliePhares, + configuration.LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions, + configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions, + configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions, + configuration.LoadOrCreateThenSaveIndex.Value, + configuration.LocationConfidenceFactor.Value, + configuration.MappedMaxIndex, + configuration.MaxItemsInDistanceCollection.Value, + configuration.MixedYearRelativePaths, + configuration.ModelDirectory, + configuration.ModelName, + configuration.NumberOfJitters.Value, + configuration.NumberOfTimesToUpsample.Value, + configuration.OutputExtension, + configuration.OutputQuality.Value, + configuration.OutputResolutions, + configuration.OverrideForFaceImages.Value, + configuration.OverrideForFaceLandmarkImages.Value, + configuration.OverrideForResizeImages.Value, + configuration.PaddingLoops.Value, + configuration.PredictorModelName, + configuration.PropertiesChangedForDistance.Value, + configuration.PropertiesChangedForFaces.Value, + configuration.PropertiesChangedForIndex.Value, + configuration.PropertiesChangedForMetadata.Value, + configuration.PropertiesChangedForResize.Value, + configuration.Reverse.Value, + configuration.SaveFaceLandmarkForOutputResolutions, + configuration.SaveFullYearOfRandomFiles.Value, + configuration.SaveResizedSubfiles.Value, + configuration.SaveShortcutsForOutputResolutions, + configuration.SkipSearch.Value, + configuration.TestDistanceResults.Value, + configuration.ValidResolutions); + return result; + } + + public static Models.Configuration Get(IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, Property.Models.Configuration propertyConfiguration) + { + Models.Configuration result; + Configuration configuration; + if (isEnvironment is null) + configuration = configurationRoot.Get(); + else + { + string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); + string section = string.Concat(environmentName, ":", nameof(Configuration)); + IConfigurationSection configurationSection = configurationRoot.GetSection(section); + configuration = configurationSection.Get(); + } + result = Get(configuration); + result.Set(propertyConfiguration); + result.Update(); + return result; + } + } \ No newline at end of file diff --git a/Tests/Models/Configuration.cs b/Tests/Models/Configuration.cs index db73b3d..a5cb689 100644 --- a/Tests/Models/Configuration.cs +++ b/Tests/Models/Configuration.cs @@ -6,136 +6,98 @@ namespace View_by_Distance.Tests.Models; public class Configuration { - protected readonly bool? _CheckJsonForDistanceResults; - protected readonly int? _CrossDirectoryMaxItemsInDistanceCollection; - protected readonly int? _DistanceFactor; - protected readonly bool? _ForceMetadataLastWriteTimeToCreationTime; - protected readonly bool? _ForceResizeLastWriteTimeToCreationTime; - protected readonly string[] _IgnoreExtensions; - protected readonly string[] _IgnoreRelativePaths; - protected readonly string[] _JuliePhares; - protected readonly string[] _LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions; - protected readonly string[] _LoadOrCreateThenSaveDistanceResultsForOutputResolutions; - protected readonly string[] _LoadOrCreateThenSaveImageFacesResultsForOutputResolutions; - protected readonly bool? _LoadOrCreateThenSaveIndex; - protected readonly int? _LocationConfidenceFactor; - protected readonly int? _MappedMaxIndex; - protected readonly int? _MaxItemsInDistanceCollection; - protected readonly string[] _MixedYearRelativePaths; - protected readonly string _ModelDirectory; - protected readonly string _ModelName; - protected readonly int? _NumberOfJitters; - protected readonly int? _NumberOfTimesToUpsample; - protected readonly string _OutputExtension; - protected readonly int? _OutputQuality; - protected readonly string[] _OutputResolutions; - protected readonly bool? _OverrideForFaceImages; - protected readonly bool? _OverrideForFaceLandmarkImages; - protected readonly bool? _OverrideForResizeImages; - protected readonly int? _PaddingLoops; - protected readonly string _PredictorModelName; - protected readonly bool? _PropertiesChangedForDistance; - protected readonly bool? _PropertiesChangedForFaces; - protected readonly bool? _PropertiesChangedForIndex; - protected readonly bool? _PropertiesChangedForMetadata; - protected readonly bool? _PropertiesChangedForResize; - protected Property.Models.Configuration? _PropertyConfiguration; - protected readonly bool? _Reverse; - protected readonly string[] _SaveFaceLandmarkForOutputResolutions; - protected readonly bool? _SaveFullYearOfRandomFiles; - protected readonly bool? _SaveResizedSubfiles; - protected readonly string[] _SaveShortcutsForOutputResolutions; - protected readonly bool? _SkipSearch; - protected readonly bool? _TestDistanceResults; - protected readonly string[] _ValidResolutions; - public bool? CheckJsonForDistanceResults => _CheckJsonForDistanceResults; - public int? CrossDirectoryMaxItemsInDistanceCollection => _CrossDirectoryMaxItemsInDistanceCollection; - public int? DistanceFactor => _DistanceFactor; - public bool? ForceMetadataLastWriteTimeToCreationTime => _ForceMetadataLastWriteTimeToCreationTime; - public bool? ForceResizeLastWriteTimeToCreationTime => _ForceResizeLastWriteTimeToCreationTime; - public string[] IgnoreExtensions => _IgnoreExtensions; - public string[] IgnoreRelativePaths => _IgnoreRelativePaths; - public string[] JuliePhares => _JuliePhares; - public string[] LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions => _LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions; - public string[] LoadOrCreateThenSaveDistanceResultsForOutputResolutions => _LoadOrCreateThenSaveDistanceResultsForOutputResolutions; - public string[] LoadOrCreateThenSaveImageFacesResultsForOutputResolutions => _LoadOrCreateThenSaveImageFacesResultsForOutputResolutions; - public bool? LoadOrCreateThenSaveIndex => _LoadOrCreateThenSaveIndex; - public int? LocationConfidenceFactor => _LocationConfidenceFactor; - public int? MappedMaxIndex => _MappedMaxIndex; - public int? MaxItemsInDistanceCollection => _MaxItemsInDistanceCollection; - public string[] MixedYearRelativePaths => _MixedYearRelativePaths; - public string ModelDirectory => _ModelDirectory; - public string ModelName => _ModelName; - public int? NumberOfJitters => _NumberOfJitters; - public int? NumberOfTimesToUpsample => _NumberOfTimesToUpsample; - public string OutputExtension => _OutputExtension; - public int? OutputQuality => _OutputQuality; - public string[] OutputResolutions => _OutputResolutions; - public bool? OverrideForFaceImages => _OverrideForFaceImages; - public bool? OverrideForFaceLandmarkImages => _OverrideForFaceLandmarkImages; - public bool? OverrideForResizeImages => _OverrideForResizeImages; - public int? PaddingLoops => _PaddingLoops; - public string PredictorModelName => _PredictorModelName; - public bool? PropertiesChangedForDistance => _PropertiesChangedForDistance; - public bool? PropertiesChangedForFaces => _PropertiesChangedForFaces; - public bool? PropertiesChangedForIndex => _PropertiesChangedForIndex; - public bool? PropertiesChangedForMetadata => _PropertiesChangedForMetadata; - public bool? PropertiesChangedForResize => _PropertiesChangedForResize; - public Property.Models.Configuration? PropertyConfiguration => _PropertyConfiguration; - public bool? Reverse => _Reverse; - public string[] SaveFaceLandmarkForOutputResolutions => _SaveFaceLandmarkForOutputResolutions; - public bool? SaveFullYearOfRandomFiles => _SaveFullYearOfRandomFiles; - public bool? SaveResizedSubfiles => _SaveResizedSubfiles; - public string[] SaveShortcutsForOutputResolutions => _SaveShortcutsForOutputResolutions; - public bool? SkipSearch => _SkipSearch; - public bool? TestDistanceResults => _TestDistanceResults; - public string[] ValidResolutions => _ValidResolutions; + protected Property.Models.Configuration _PropertyConfiguration; + public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration; + + public bool CheckJsonForDistanceResults { init; get; } + public int CrossDirectoryMaxItemsInDistanceCollection { init; get; } + public int DistanceFactor { init; get; } + public bool ForceFaceLastWriteTimeToCreationTime { init; get; } + public bool ForceMetadataLastWriteTimeToCreationTime { init; get; } + public bool ForceResizeLastWriteTimeToCreationTime { init; get; } + public string[] IgnoreExtensions { init; get; } + public string[] IgnoreRelativePaths { init; get; } + public string[] JuliePhares { init; get; } + public string[] LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions { init; get; } + public string[] LoadOrCreateThenSaveDistanceResultsForOutputResolutions { init; get; } + public string[] LoadOrCreateThenSaveImageFacesResultsForOutputResolutions { init; get; } + public bool LoadOrCreateThenSaveIndex { init; get; } + public int LocationConfidenceFactor { init; get; } + public int? MappedMaxIndex { init; get; } + public int MaxItemsInDistanceCollection { init; get; } + public string[] MixedYearRelativePaths { init; get; } + public string ModelDirectory { init; get; } + public string ModelName { init; get; } + public int NumberOfJitters { init; get; } + public int NumberOfTimesToUpsample { init; get; } + public string OutputExtension { init; get; } + public int OutputQuality { init; get; } + public string[] OutputResolutions { init; get; } + public bool OverrideForFaceImages { init; get; } + public bool OverrideForFaceLandmarkImages { init; get; } + public bool OverrideForResizeImages { init; get; } + public int PaddingLoops { init; get; } + public string PredictorModelName { init; get; } + public bool PropertiesChangedForDistance { init; get; } + public bool PropertiesChangedForFaces { init; get; } + public bool PropertiesChangedForIndex { init; get; } + public bool PropertiesChangedForMetadata { init; get; } + public bool PropertiesChangedForResize { init; get; } + public bool Reverse { init; get; } + public string[] SaveFaceLandmarkForOutputResolutions { init; get; } + public bool SaveFullYearOfRandomFiles { init; get; } + public bool SaveResizedSubfiles { init; get; } + public string[] SaveShortcutsForOutputResolutions { init; get; } + public bool SkipSearch { init; get; } + public bool TestDistanceResults { init; get; } + public string[] ValidResolutions { init; get; } [JsonConstructor] - public Configuration(bool? checkJsonForDistanceResults, int? crossDirectoryMaxItemsInDistanceCollection, int? distanceFactor, bool? forceMetadataLastWriteTimeToCreationTime, bool? forceResizeLastWriteTimeToCreationTime, string[] ignoreExtensions, string[] ignoreRelativePaths, string[] juliePhares, string[] loadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions, string[] loadOrCreateThenSaveDistanceResultsForOutputResolutions, string[] loadOrCreateThenSaveImageFacesResultsForOutputResolutions, bool? loadOrCreateThenSaveIndex, int? locationConfidenceFactor, int? mappedMaxIndex, int? maxItemsInDistanceCollection, string[] mixedYearRelativePaths, string modelDirectory, string modelName, int? numberOfJitters, int? numberOfTimesToUpsample, string outputExtension, int? outputQuality, string[] outputResolutions, bool? overrideForFaceImages, bool? overrideForFaceLandmarkImages, bool? overrideForResizeImages, int? paddingLoops, string predictorModelName, bool? propertiesChangedForDistance, bool? propertiesChangedForFaces, bool? propertiesChangedForIndex, bool? propertiesChangedForMetadata, bool? propertiesChangedForResize, Property.Models.Configuration? propertyConfiguration, bool? reverse, string[] saveFaceLandmarkForOutputResolutions, bool? saveFullYearOfRandomFiles, bool? saveResizedSubfiles, string[] saveShortcutsForOutputResolutions, bool? skipSearch, bool? testDistanceResults, string[] validResolutions) + public Configuration(Property.Models.Configuration propertyConfiguration, bool checkJsonForDistanceResults, int crossDirectoryMaxItemsInDistanceCollection, int distanceFactor, bool forceFaceLastWriteTimeToCreationTime, bool forceMetadataLastWriteTimeToCreationTime, bool forceResizeLastWriteTimeToCreationTime, string[] ignoreExtensions, string[] ignoreRelativePaths, string[] juliePhares, string[] loadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions, string[] loadOrCreateThenSaveDistanceResultsForOutputResolutions, string[] loadOrCreateThenSaveImageFacesResultsForOutputResolutions, bool loadOrCreateThenSaveIndex, int locationConfidenceFactor, int? mappedMaxIndex, int maxItemsInDistanceCollection, string[] mixedYearRelativePaths, string modelDirectory, string modelName, int numberOfJitters, int numberOfTimesToUpsample, string outputExtension, int outputQuality, string[] outputResolutions, bool overrideForFaceImages, bool overrideForFaceLandmarkImages, bool overrideForResizeImages, int paddingLoops, string predictorModelName, bool propertiesChangedForDistance, bool propertiesChangedForFaces, bool propertiesChangedForIndex, bool propertiesChangedForMetadata, bool propertiesChangedForResize, bool reverse, string[] saveFaceLandmarkForOutputResolutions, bool saveFullYearOfRandomFiles, bool saveResizedSubfiles, string[] saveShortcutsForOutputResolutions, bool skipSearch, bool testDistanceResults, string[] validResolutions) { - _CheckJsonForDistanceResults = checkJsonForDistanceResults; - _CrossDirectoryMaxItemsInDistanceCollection = crossDirectoryMaxItemsInDistanceCollection; - _DistanceFactor = distanceFactor; - _ForceMetadataLastWriteTimeToCreationTime = forceMetadataLastWriteTimeToCreationTime; - _ForceResizeLastWriteTimeToCreationTime = forceResizeLastWriteTimeToCreationTime; - _IgnoreExtensions = ignoreExtensions; - _IgnoreRelativePaths = ignoreRelativePaths; - _JuliePhares = juliePhares; - _LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions = loadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions; - _LoadOrCreateThenSaveDistanceResultsForOutputResolutions = loadOrCreateThenSaveDistanceResultsForOutputResolutions; - _LoadOrCreateThenSaveImageFacesResultsForOutputResolutions = loadOrCreateThenSaveImageFacesResultsForOutputResolutions; - _LoadOrCreateThenSaveIndex = loadOrCreateThenSaveIndex; - _LocationConfidenceFactor = locationConfidenceFactor; - _MappedMaxIndex = mappedMaxIndex; - _MaxItemsInDistanceCollection = maxItemsInDistanceCollection; - _MixedYearRelativePaths = mixedYearRelativePaths; - _ModelDirectory = modelDirectory; - _ModelName = modelName; - _NumberOfJitters = numberOfJitters; - _NumberOfTimesToUpsample = numberOfTimesToUpsample; - _OutputExtension = outputExtension; - _OutputQuality = outputQuality; - _OutputResolutions = outputResolutions; - _OverrideForFaceImages = overrideForFaceImages; - _OverrideForFaceLandmarkImages = overrideForFaceLandmarkImages; - _OverrideForResizeImages = overrideForResizeImages; - _PaddingLoops = paddingLoops; - _PredictorModelName = predictorModelName; - _PropertiesChangedForDistance = propertiesChangedForDistance; - _PropertiesChangedForFaces = propertiesChangedForFaces; - _PropertiesChangedForIndex = propertiesChangedForIndex; - _PropertiesChangedForMetadata = propertiesChangedForMetadata; - _PropertiesChangedForResize = propertiesChangedForResize; _PropertyConfiguration = propertyConfiguration; - _Reverse = reverse; - _SaveFaceLandmarkForOutputResolutions = saveFaceLandmarkForOutputResolutions; - _SaveFullYearOfRandomFiles = saveFullYearOfRandomFiles; - _SaveResizedSubfiles = saveResizedSubfiles; - _SaveShortcutsForOutputResolutions = saveShortcutsForOutputResolutions; - _SkipSearch = skipSearch; - _TestDistanceResults = testDistanceResults; - _ValidResolutions = validResolutions; + CheckJsonForDistanceResults = checkJsonForDistanceResults; + CrossDirectoryMaxItemsInDistanceCollection = crossDirectoryMaxItemsInDistanceCollection; + DistanceFactor = distanceFactor; + ForceFaceLastWriteTimeToCreationTime = forceFaceLastWriteTimeToCreationTime; + ForceMetadataLastWriteTimeToCreationTime = forceMetadataLastWriteTimeToCreationTime; + ForceResizeLastWriteTimeToCreationTime = forceResizeLastWriteTimeToCreationTime; + IgnoreExtensions = ignoreExtensions; + IgnoreRelativePaths = ignoreRelativePaths; + JuliePhares = juliePhares; + LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions = loadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions; + LoadOrCreateThenSaveDistanceResultsForOutputResolutions = loadOrCreateThenSaveDistanceResultsForOutputResolutions; + LoadOrCreateThenSaveImageFacesResultsForOutputResolutions = loadOrCreateThenSaveImageFacesResultsForOutputResolutions; + LoadOrCreateThenSaveIndex = loadOrCreateThenSaveIndex; + LocationConfidenceFactor = locationConfidenceFactor; + MappedMaxIndex = mappedMaxIndex; + MaxItemsInDistanceCollection = maxItemsInDistanceCollection; + MixedYearRelativePaths = mixedYearRelativePaths; + ModelDirectory = modelDirectory; + ModelName = modelName; + NumberOfJitters = numberOfJitters; + NumberOfTimesToUpsample = numberOfTimesToUpsample; + OutputExtension = outputExtension; + OutputQuality = outputQuality; + OutputResolutions = outputResolutions; + OverrideForFaceImages = overrideForFaceImages; + OverrideForFaceLandmarkImages = overrideForFaceLandmarkImages; + OverrideForResizeImages = overrideForResizeImages; + PaddingLoops = paddingLoops; + PredictorModelName = predictorModelName; + PropertiesChangedForDistance = propertiesChangedForDistance; + PropertiesChangedForFaces = propertiesChangedForFaces; + PropertiesChangedForIndex = propertiesChangedForIndex; + PropertiesChangedForMetadata = propertiesChangedForMetadata; + PropertiesChangedForResize = propertiesChangedForResize; + Reverse = reverse; + SaveFaceLandmarkForOutputResolutions = saveFaceLandmarkForOutputResolutions; + SaveFullYearOfRandomFiles = saveFullYearOfRandomFiles; + SaveResizedSubfiles = saveResizedSubfiles; + SaveShortcutsForOutputResolutions = saveShortcutsForOutputResolutions; + SkipSearch = skipSearch; + TestDistanceResults = testDistanceResults; + ValidResolutions = validResolutions; } public override string ToString() @@ -146,6 +108,6 @@ public class Configuration public void Set(Property.Models.Configuration configuration) => _PropertyConfiguration = configuration; - public void Update() => _PropertyConfiguration?.Update(); + public void Update() => _PropertyConfiguration.Update(); } \ No newline at end of file diff --git a/Tests/Models/Stateless/Configuration.cs b/Tests/Models/Stateless/Configuration.cs deleted file mode 100644 index 030de3f..0000000 --- a/Tests/Models/Stateless/Configuration.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Microsoft.Extensions.Configuration; -using Phares.Shared; -using System.Text.Json; - -namespace View_by_Distance.Tests.Models.Stateless; - -public abstract class Configuration -{ - - public static Models.Configuration Get(IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, string workingDirectory, Property.Models.Configuration propertyConfiguration) - { - Models.Configuration? result; - string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); - string section = string.Concat(environmentName, ":", nameof(Binder.Configuration)); - IConfigurationSection configurationSection = configurationRoot.GetSection(section); - Binder.Configuration configuration = configurationSection.Get(); - string json = JsonSerializer.Serialize(configuration, new JsonSerializerOptions() { WriteIndented = true }); - result = JsonSerializer.Deserialize(json); - if (result is null) - throw new Exception(json); - string jsonThis = result.ToString(); - result.Set(propertyConfiguration); - result.Update(); - if (jsonThis != json) - { - int? check = null; - int min = new int[] { json.Length, jsonThis.Length }.Min(); - for (int i = 0; i < min; i++) - { - if (json[i] == jsonThis[i]) - continue; - check = i; - break; - } - if (check is null) - throw new Exception(); - string a = json[..check.Value].Split(',')[^1]; - string b = json[check.Value..].Split(',')[0]; - throw new Exception($"{a}{b}"); - } - return result; - } - -} \ No newline at end of file diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 25b9e74..777179b 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -7,6 +7,11 @@ win-x64 net6.0 + + trx + XPlat Code Coverage + ../.vscode/TestResults + true true @@ -42,10 +47,13 @@ - + Always - + + Always + + Always diff --git a/Tests/UnitTestExample.cs b/Tests/UnitTestExample.cs index e9deb2e..ca752f0 100644 --- a/Tests/UnitTestExample.cs +++ b/Tests/UnitTestExample.cs @@ -44,8 +44,8 @@ public class UnitTestExample _ = ConfigurationLoggerConfigurationExtensions.Configuration(loggerConfiguration.ReadFrom, configurationRoot); Log.Logger = loggerConfiguration.CreateLogger(); logger = Log.ForContext(); - propertyConfiguration = Property.Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory); - configuration = Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory, propertyConfiguration); + propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot); + configuration = Models.Binder.Configuration.Get(isEnvironment, configurationRoot, propertyConfiguration); logger.Information("Complete"); _Logger = logger; _AppSettings = appSettings; diff --git a/Tests/UnitTestIsEnvironment.cs b/Tests/UnitTestIsEnvironment.cs new file mode 100644 index 0000000..086b28b --- /dev/null +++ b/Tests/UnitTestIsEnvironment.cs @@ -0,0 +1,104 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration.Json; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Phares.Shared; +using Serilog; +using System.Diagnostics; +using System.Reflection; +using View_by_Distance.Shared.Models.Stateless.Methods; +using View_by_Distance.Tests.Models; + +namespace View_by_Distance.Tests; + +[TestClass] +public class UnitTestIsEnvironment +{ + + private readonly ILogger _Logger; + private readonly AppSettings _AppSettings; + private readonly string _WorkingDirectory; + private readonly IConfigurationRoot _ConfigurationRoot; + + public UnitTestIsEnvironment() + { + ILogger logger; + AppSettings appSettings; + string workingDirectory; + IConfigurationRoot configurationRoot; + LoggerConfiguration loggerConfiguration = new(); + Assembly assembly = Assembly.GetExecutingAssembly(); + IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() + .AddEnvironmentVariables() + .AddJsonFile("appsettings.Development.json"); + configurationRoot = configurationBuilder.Build(); + appSettings = Models.Binder.AppSettings.Get(configurationRoot); + workingDirectory = IWorkingDirectory.GetWorkingDirectory(assembly.GetName().Name, appSettings.WorkingDirectoryName); + Environment.SetEnvironmentVariable(nameof(workingDirectory), workingDirectory); + _ = ConfigurationLoggerConfigurationExtensions.Configuration(loggerConfiguration.ReadFrom, configurationRoot); + Log.Logger = loggerConfiguration.CreateLogger(); + logger = Log.ForContext(); + logger.Information("Complete"); + _Logger = logger; + _AppSettings = appSettings; + _WorkingDirectory = workingDirectory; + _ConfigurationRoot = configurationRoot; + } + + [TestMethod] + public void TestMethodNull() + { + Assert.IsFalse(_Logger is null); + Assert.IsFalse(_AppSettings is null); + Assert.IsFalse(_WorkingDirectory is null); + Assert.IsFalse(_ConfigurationRoot is null); + } + + [TestMethod] + public void TestMethodTest() + { + List jsonFiles = new(); + foreach (IConfigurationProvider configurationProvider in _ConfigurationRoot.Providers) + { + if (configurationProvider is not JsonConfigurationProvider jsonConfigurationProvider) + continue; + jsonFiles.Add(jsonConfigurationProvider.Source.Path); + } + Assert.IsTrue(jsonFiles.Any()); + foreach (string jsonFile in jsonFiles) + _ = new IsEnvironment(jsonFile); + } + + [TestMethod] + [TestCategory(nameof(IsEnvironment.Name.WindowsDevelopment))] + public void TestMethodTestCategory() + { + MethodBase? methodBase = new StackFrame().GetMethod(); + if (methodBase is not null) + { + TestCategoryAttribute? testCategoryAttribute = methodBase.GetCustomAttribute(); + if (testCategoryAttribute is not null) + { + foreach (string testCategory in testCategoryAttribute.TestCategories) + _ = new IsEnvironment(testCategory); + } + } + } + + [TestMethod] + public void TestMethodHardcoded() + { + _ = new IsEnvironment(isDevelopment: true, isStaging: false, isProduction: false); + _ = new IsEnvironment(isDevelopment: false, isStaging: true, isProduction: false); + _ = new IsEnvironment(isDevelopment: false, isStaging: false, isProduction: true); + } + + [TestMethod] + public void TestMethodAssembly() + { + Assembly assembly = Assembly.GetExecutingAssembly(); + bool debuggerWasAttachedAtLineZero = Debugger.IsAttached || assembly.Location.Contains(@"\bin\Debug"); + IsEnvironment isEnvironment = new(processesCount: null, nullASPNetCoreEnvironmentIsDevelopment: debuggerWasAttachedAtLineZero, nullASPNetCoreEnvironmentIsProduction: !debuggerWasAttachedAtLineZero); + _ = IsEnvironment.GetEnvironmentName(isEnvironment); + } + +} \ No newline at end of file diff --git a/Tests/UnitTestResize.cs b/Tests/UnitTestResize.cs index 7f59417..a45a62a 100644 --- a/Tests/UnitTestResize.cs +++ b/Tests/UnitTestResize.cs @@ -7,6 +7,7 @@ using System.Drawing.Imaging; using System.Reflection; using View_by_Distance.Metadata.Models; using View_by_Distance.Resize.Models; +using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Stateless; using View_by_Distance.Shared.Models.Stateless.Methods; using View_by_Distance.Tests.Models; @@ -48,8 +49,8 @@ public class UnitTestResize _ = ConfigurationLoggerConfigurationExtensions.Configuration(loggerConfiguration.ReadFrom, configurationRoot); Log.Logger = loggerConfiguration.CreateLogger(); logger = Log.ForContext(); - propertyConfiguration = Property.Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory); - configuration = Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory, propertyConfiguration); + propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot); + configuration = Models.Binder.Configuration.Get(isEnvironment, configurationRoot, propertyConfiguration); logger.Information("Complete"); _Logger = logger; _AppSettings = appSettings; @@ -72,12 +73,97 @@ public class UnitTestResize Assert.IsFalse(_PropertyConfiguration is null); } - private Property.Models.PropertyLogic GetPropertyLogic(bool reverse, Model? model, PredictorModel? predictorModel) + [TestMethod] + public void TestGetLocation() { - Property.Models.PropertyLogic result; + double confidence = 0.1D; + int left, top, right, bottom, width, height; + left = 20; + top = 40; + right = 60; + bottom = 80; + width = 100; + height = 100; + Location location = new(bottom, confidence, left, null, right, top); + _ = new Location(confidence, height, location, width, 1); + _ = new Location(bottom, confidence, height, left, right, top, width, 1); + } + + [TestMethod] + public void TestGetPixelPercentage() + { + int normalizedPixelPercentage; + int left, top, right, bottom, width, height; + left = 1; + top = 1; + right = 10; + bottom = 10; + width = 100; + height = 100; + normalizedPixelPercentage = Location.GetNormalizedPixelPercentage(bottom, height, left, right, top, width, 1); + Assert.IsTrue(normalizedPixelPercentage == 40500); + left = 50; + top = 50; + right = 60; + bottom = 60; + width = 100; + height = 100; + normalizedPixelPercentage = Location.GetNormalizedPixelPercentage(bottom, height, left, right, top, width, 1); + Assert.IsTrue(normalizedPixelPercentage == 545500); + } + + [TestMethod] + public void TestGetPixelPercentageB() + { + int normalizedPixelPercentage; + int left, top, right, bottom, width, height; + left = 240; + top = 240; + right = 260; + bottom = 260; + width = 500; + height = 500; + normalizedPixelPercentage = Location.GetNormalizedPixelPercentage(bottom, height, left, right, top, width, 1); + Assert.IsTrue(normalizedPixelPercentage == 499000); + left = 490; + top = 490; + right = 510; + bottom = 510; + width = 1000; + height = 1000; + normalizedPixelPercentage = Location.GetNormalizedPixelPercentage(bottom, height, left, right, top, width, 1); + Assert.IsTrue(normalizedPixelPercentage == 499500); + } + + [TestMethod] + public void TestGetPixelPercentageC() + { + int normalizedPixelPercentage; + int left, top, right, bottom, width, height; + left = 20; + top = 40; + right = 60; + bottom = 80; + width = 100; + height = 100; + normalizedPixelPercentage = Location.GetNormalizedPixelPercentage(bottom, height, left, right, top, width, 1); + Assert.IsTrue(normalizedPixelPercentage == 594000); + left = 20; + top = 40; + right = 60; + bottom = 80; + width = 100; + height = 100; + normalizedPixelPercentage = Location.GetNormalizedPixelPercentage(bottom, height, left, right, top, width, 10); + Assert.IsTrue(normalizedPixelPercentage == 594000); + } + + private Property.Models.A_Property GetPropertyLogic(bool reverse, Model? model, PredictorModel? predictorModel) + { + Property.Models.A_Property result; if (_Configuration?.PropertyConfiguration is null) throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration)); - result = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, reverse, model, predictorModel); + result = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Configuration.OutputExtension, reverse, model, predictorModel); return result; } @@ -88,21 +174,9 @@ public class UnitTestResize // string sourceDirectoryName = "Mackenzie Prom 2017"; string sourceFileName = "Fall 2005 (113).jpg"; string sourceDirectoryName = "=2005.3 Fall"; - if (_Configuration.ForceMetadataLastWriteTimeToCreationTime is null) - throw new NullReferenceException(nameof(_Configuration.ForceMetadataLastWriteTimeToCreationTime)); - if (_Configuration.ForceResizeLastWriteTimeToCreationTime is null) - throw new NullReferenceException(nameof(_Configuration.ForceResizeLastWriteTimeToCreationTime)); - if (_Configuration.OutputQuality is null) - throw new NullReferenceException(nameof(_Configuration.OutputQuality)); - if (_Configuration.OverrideForResizeImages is null) - throw new NullReferenceException(nameof(_Configuration.OverrideForResizeImages)); - if (_Configuration.PropertiesChangedForMetadata is null) - throw new NullReferenceException(nameof(_Configuration.PropertiesChangedForMetadata)); - if (_Configuration.PropertiesChangedForResize is null) - throw new NullReferenceException(nameof(_Configuration.PropertiesChangedForResize)); + Item item; Model? model = null; bool reverse = false; - Property.Models.Item item; string original = "Original"; string aResultsFullGroupDirectory; string bResultsFullGroupDirectory; @@ -110,13 +184,13 @@ public class UnitTestResize List parseExceptions = new(); PredictorModel? predictorModel = null; bool isValidImageFormatExtension = true; - Property.Models.A_Property? property = null; + Shared.Models.Property? property = null; Dictionary imageResizeKeyValuePairs; List> subFileTuples = new(); List> metadataCollection; int length = _PropertyConfiguration.RootDirectory.Length; string outputResolution = _Configuration.OutputResolutions[0]; - Property.Models.PropertyLogic propertyLogic = GetPropertyLogic(reverse, model, predictorModel); + Property.Models.A_Property propertyLogic = GetPropertyLogic(reverse, model, predictorModel); string sourceDirectory = Path.Combine(_PropertyConfiguration.RootDirectory, sourceDirectoryName); _Logger.Information(_Configuration.ModelDirectory); aResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( @@ -126,9 +200,11 @@ public class UnitTestResize cResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( _PropertyConfiguration, model, predictorModel, nameof(C_Resize), outputResolution, includeResizeGroup: true, includeModel: false, includePredictorModel: false); string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_PropertyConfiguration, nameof(Property.Models.A_Property), "{}"); - B_Metadata metadata = new(_Configuration.ForceMetadataLastWriteTimeToCreationTime.Value, _Configuration.PropertiesChangedForMetadata.Value); - (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters) = C_Resize.GetTuple(_Configuration.OutputExtension, _Configuration.OutputQuality.Value); - C_Resize resize = new(_Configuration.ForceResizeLastWriteTimeToCreationTime.Value, _Configuration.OverrideForResizeImages.Value, _Configuration.PropertiesChangedForResize.Value, _Configuration.ValidResolutions, imageCodecInfo, encoderParameters); + B_Metadata metadata = new(_Configuration.ForceMetadataLastWriteTimeToCreationTime, _Configuration.PropertiesChangedForMetadata); + _ = metadata.ToString(); + (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) = C_Resize.GetTuple(_Configuration.OutputExtension, _Configuration.OutputQuality); + C_Resize resize = new(_Configuration.ForceResizeLastWriteTimeToCreationTime, _Configuration.OverrideForResizeImages, _Configuration.PropertiesChangedForResize, _Configuration.ValidResolutions, imageCodecInfo, encoderParameters, filenameExtension); + _ = resize.ToString(); propertyLogic.AngleBracketCollection.AddRange(Property.Models.Stateless.IResult.GetDirectoryInfoCollection( _PropertyConfiguration, sourceDirectory, @@ -154,8 +230,8 @@ public class UnitTestResize collectionDescription: string.Empty, converted: true)); string sourceDirectoryFile = ".json"; - Property.Models.FileHolder fileHolder = new(Path.Combine(sourceDirectory, sourceFileName)); - string relativePath = Property.Models.Stateless.IPath.GetRelativePath(fileHolder.FullName, length); + FileHolder fileHolder = new(Path.Combine(sourceDirectory, sourceFileName)); + string relativePath = IPath.GetRelativePath(fileHolder.FullName, length); sourceDirectory = Path.Combine(aPropertySingletonDirectory, sourceDirectoryName); item = new(sourceDirectoryFile, relativePath, fileHolder, isValidImageFormatExtension, property, false, false); Assert.IsNotNull(item.ImageFileHolder); @@ -166,10 +242,10 @@ public class UnitTestResize } (int _, metadataCollection) = metadata.GetMetadataCollection(bResultsFullGroupDirectory, subFileTuples, parseExceptions, item); imageResizeKeyValuePairs = resize.GetResizeKeyValuePairs(cResultsFullGroupDirectory, subFileTuples, parseExceptions, original, metadataCollection, item); - Property.Models.FileHolder resizedFileHolder = new(Path.Combine(resize.AngleBracketCollection[0].Replace("<>", "()"), Path.GetFileName(item.ImageFileHolder.FullName))); - item.SetResizedFileHolder(resizedFileHolder); + FileHolder resizedFileHolder = new(Path.Combine(resize.AngleBracketCollection[0].Replace("<>", "()"), Path.GetFileName(item.ImageFileHolder.FullName))); + item.SetResizedFileHolder(resize.FilenameExtension, resizedFileHolder); resize.SaveResizedSubfile(outputResolution, cResultsFullGroupDirectory, subFileTuples, item, original, imageResizeKeyValuePairs); - item.SetResizedFileHolder(Property.Models.FileHolder.Refresh(resizedFileHolder)); + item.SetResizedFileHolder(resize.FilenameExtension, IFileHolder.Refresh(resizedFileHolder)); } } \ No newline at end of file diff --git a/Tests/appsettings.Development.json b/Tests/appsettings.Development.json deleted file mode 100644 index 81aad60..0000000 --- a/Tests/appsettings.Development.json +++ /dev/null @@ -1,526 +0,0 @@ -{ - "Company": "Mike Phares", - "Linux": {}, - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Log4netProvider": "Debug", - "Microsoft.Hosting.Lifetime": "Information" - } - }, - "MaxDegreeOfParallelism": 6, - "Serilog": { - "Using": [ - "Serilog.Sinks.Console", - "Serilog.Sinks.File" - ], - "MinimumLevel": "Debug", - "WriteTo": [ - { - "Name": "Debug", - "Args": { - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" - } - }, - { - "Name": "Console", - "Args": { - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" - } - }, - { - "Name": "File", - "Args": { - "path": "%workingDirectory% - Log/log-.txt", - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}", - "rollingInterval": "Hour" - } - } - ], - "Enrich": [ - "FromLogContext", - "WithMachineName", - "WithThreadId" - ], - "Properties": { - "Application": "Sample" - } - }, - "WorkingDirectoryName": "PharesApps", - "Windows": { - "Configuration": { - "CheckJsonForDistanceResults": false, - "CrossDirectoryMaxItemsInDistanceCollection": 7, - "DateGroup": "2022-08-14", - "DistanceFactor": 8, - "FileNameDirectorySeparator": ".Z.", - "ForceMetadataLastWriteTimeToCreationTime": true, - "ForcePropertyLastWriteTimeToCreationTime": false, - "ForceResizeLastWriteTimeToCreationTime": true, - "LoadOrCreateThenSaveIndex": false, - "LocationConfidenceFactor": 2, - "MappedMaxIndex": 1034720, - "MaxImagesInDirectoryForTopLevelFirstPass": 50, - "MaxItemsInDistanceCollection": 50, - "ModelDirectory": "C:/GitHub/dlib-models", - "ModelName": "Hog", - "NumberOfJitters": 1, - "NumberOfTimesToUpsample": 1, - "OutputExtension": ".jpg", - "OutputQuality": 95, - "OverrideForFaceImages": false, - "OverrideForFaceLandmarkImages": false, - "OverrideForResizeImages": false, - "PaddingLoops": 5, - "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", - "PredictorModelName": "Large", - "PopulatePropertyId": true, - "PropertiesChangedForDistance": false, - "PropertiesChangedForFaces": false, - "PropertiesChangedForIndex": false, - "PropertiesChangedForMetadata": false, - "PropertiesChangedForProperty": false, - "PropertiesChangedForResize": false, - "Reverse": false, - "xRootDirectory": "C:/Tmp/phares/Pictures", - "RootDirectory": "F:/Tmp/Phares/Compare/Images 2022-08-14 - b756859b616424dc98b7742a64c15a8951632473 - III", - "SaveFullYearOfRandomFiles": true, - "SaveResizedSubFiles": true, - "SkipSearch": false, - "TestDistanceResults": true, - "WriteBitmapDataBytes": false, - "IgnoreExtensions": [ - ".gif", - ".GIF" - ], - "JuliePhares": [ - "1500-01-16_00", - "1500-01-19_00", - "1500-01-20_00", - "1500-01-21_00", - "1500-01-25_00", - "1500-01-26_00", - "1500-01-27_00", - "1500-02-13_00", - "1500-02-17_00", - "1500-02-24_00", - "1500-02-25_00", - "1500-04-03_00", - "1500-04-06_00", - "1500-04-19_00", - "1500-05-03_00", - "1500-05-18_00", - "1500-05-28_00", - "1500-06-16_00", - "1500-06-26_00", - "1500-06-27_00", - "1500-07-07_00", - "1500-07-16_00", - "1720-09-30_05", - "1500-07-26_00", - "1500-08-03_00", - "1500-08-23_00", - "1500-08-24_00", - "1500-09-16_00", - "1500-09-21_00", - "1500-09-28_00", - "1500-10-14_00", - "1500-11-07_00", - "1500-11-09_00", - "1720-09-28_20", - "1501-01-08_00", - "1501-01-12_00", - "1501-01-13_00", - "1501-01-30_00", - "1501-03-09_00", - "1501-03-14_00", - "1501-03-22_00", - "1501-04-07_00", - "1501-04-10_00", - "1501-04-19_00", - "1501-05-06_00", - "1956-09-19_00", - "2012-09-17_00", - "1998-05-21_00", - "1960-03-01_00", - "1976-03-08_00", - "2007-09-07_00", - "2000-04-07_00", - "1980-01-17_00", - "1958-01-30_00", - "1976-01-05_00", - "1982-05-02_00" - ], - "LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions": [ - "1920 x 1080" - ], - "LoadOrCreateThenSaveDistanceResultsForOutputResolutions": [ - "1920 x 1080" - ], - "LoadOrCreateThenSaveImageFacesResultsForOutputResolutions": [ - "1920 x 1080" - ], - "OutputResolutions": [ - "176 x 176", - "256 x 256", - "353 x 353", - "1024 x 768", - "1920 x 1080" - ], - "PropertyContentCollectionFiles": [], - "SaveFaceLandmarkForOutputResolutions": [ - "176 x 176", - "256 x 256" - ], - "SaveShortcutsForOutputResolutions": [ - "1920 x 1080" - ], - "ValidImageFormatExtensions": [ - ".bmp", - ".BMP", - ".gif", - ".GIF", - ".jpeg", - ".JPEG", - ".jpg", - ".JPG", - ".png", - ".PNG", - ".tiff", - ".TIFF" - ], - "ValidMetadataExtensions": [ - ".3gp", - ".3GP", - ".amr", - ".AMR", - ".avi", - ".AVI", - ".bmp", - ".BMP", - ".gif", - ".GIF", - ".ico", - ".ICO", - ".jpeg", - ".JPEG", - ".jpg", - ".JPG", - ".m4v", - ".M4V", - ".mov", - ".MOV", - ".mp4", - ".MP4", - ".mta", - ".MTA", - ".png", - ".PNG", - ".tiff", - ".TIFF" - ], - "ValidResolutions": [ - "176 x 176", - "256 x 256", - "353 x 353", - "1024 x 768", - "1280 x 720", - "1280 x 800", - "1376 x 768", - "1600 x 1200", - "1920 x 1080", - "2256 x 1496", - "3840 x 2160", - "7680 x 4320" - ], - "VerifyToSeason": [ - ". 2000", - ". 2001", - ". 2002", - ". 2003", - ". 2004", - ". 2005", - ". 2006", - ". 2007", - ". 2008", - ". 2009", - ". 2010", - ". 2011", - ". 2012", - ". 2013", - ". 2014", - ". 2015", - ". 2016", - ". 2017", - ". 2018", - ". 2019", - ". 2020", - ". 2021", - ". 2022", - ". 2023", - ". 2024", - ". 2025", - ". 2026", - ". 2027", - ". 2028", - ". 2029", - "=2000.0 Winter", - "=2002.1 Spring", - "=2002.4 Winter", - "=2003.0 Winter", - "=2003.1 Spring", - "=2003.3 Fall", - "=2003.4 Winter", - "=2004.0 Winter", - "=2005.1 Spring", - "=2005.2 Summer", - "=2005.3 Fall", - "=2005.4 Winter", - "=2006.0 Winter", - "=2006.1 Spring", - "=2006.3 Fall", - "=2007.0 Winter", - "=2007.2 Summer Logan Michael", - "=2007.2 Summer", - "=2007.3 Fall Logan Michael", - "=2007.4 Winter Logan Michael", - "=2008.0 Winter Logan Michael", - "=2008.1 Spring Logan Michael", - "=2008.2 Summer Logan Michael", - "=2008.2 Summer", - "=2008.3 Fall Logan Michael", - "=2009.0 Winter Logan Michael", - "=2009.0 Winter", - "=2009.1 Spring Logan Michael", - "=2009.1 Spring", - "=2009.2 Summer Logan Michael", - "=2009.2 Summer", - "=2009.3 Fall Logan Michael", - "=2009.3 Fall", - "=2009.4 Winter Logan Michael", - "=2009.4 Winter", - "=2010.0 Winter Logan Michael", - "=2010.0 Winter", - "=2010.1 Spring Logan Michael", - "=2010.1 Spring", - "=2010.2 Summer", - "=2010.3 Fall Logan Michael", - "=2010.3 Fall", - "=2010.4 Winter", - "=2011.0 Winter", - "=2011.1 Spring", - "=2011.2 Summer", - "=2011.3 Fall", - "=2011.4 Winter", - "=2012.0 Winter Chelsea 2012", - "=2012.0 Winter Chelsea", - "=2012.0 Winter", - "=2012.1 Spring Chelsea", - "=2012.1 Spring", - "=2012.2 Summer Chelsea", - "=2012.2 Summer", - "=2012.3 Fall Chelsea", - "=2012.3 Fall", - "=2012.4 Winter Chelsea", - "=2012.4 Winter", - "=2013.0 Winter Chelsea 2013", - "=2013.0 Winter Chelsea", - "=2013.0 Winter", - "=2013.1 Spring", - "=2013.2 Summer Chelsea", - "=2013.2 Summer", - "=2013.3 Fall Chelsea", - "=2013.3 Fall", - "=2013.4 Winter", - "=2014.0 Winter", - "=2014.1 Spring", - "=2014.2 Summer", - "=2014.3 Fall", - "=2014.4 Winter", - "=2015.0 Winter", - "=2015.1 Spring", - "=2015.2 Summer", - "=2015.3 Fall", - "=2015.4 Winter", - "=2016.0 Winter", - "=2016.1 Spring", - "=2016.2 Summer", - "=2016.3 Fall", - "=2016.4 Winter", - "=2017.1 Spring", - "=2017.2 Summer", - "=2017.3 Fall", - "=2017.4 Winter", - "=2018.0 Winter", - "=2018.1 Spring", - "=2018.3 Fall", - "=2018.4 Winter", - "=2019.0 Winter", - "=2019.1 Spring", - "=2019.2 Summer", - "=2019.3 Fall", - "=2019.4 Winter", - "=2020.0 Winter", - "=2020.1 Spring", - "=2020.2 Summer", - "=2020.3 Fall", - "=2020.4 Winter", - "=2021.1 Spring", - "=2021.2 Summer", - "=2021.3 Fall", - "=2021.4 Winter", - "=2022.0 Winter", - "=2022.1 Spring", - "Anthem 2015", - "April 2010", - "April 2013", - "December 2006", - "December 2010", - "Fall 2005", - "Fall 2015", - "Fall 2016", - "Fall 2017", - "Fall 2018", - "Fall 2019", - "Fall 2020", - "Fall 2021", - "February 2010", - "January 2015", - "July 2010", - "June 2010", - "Kids 2005", - "March 2013", - "May 2010", - "May 2011", - "May 2013", - "October 2005", - "October 2014", - "Spring 2013", - "Spring 2014", - "Spring 2016", - "Spring 2018", - "Spring 2019", - "Spring 2020", - "Summer 2011", - "Summer 2012", - "Summer 2013", - "Summer 2014", - "Summer 2015", - "Summer 2016", - "Summer 2017", - "Summer 2018", - "Summer 2020", - "Summer 2021", - "Winter 2015", - "Winter 2016", - "Winter 2017", - "Winter 2018", - "Winter 2019-2020", - "Winter 2020", - "zzz =2005.0 Winter Tracy Pictures", - "zzz =2005.1 Spring Tracy Pictures", - "zzz =2005.2 Summer Tracy Pictures", - "zzz =2005.3 Fall Tracy Pictures", - "zzz =2005.4 Winter Tracy Pictures", - "zzz =2006.1 Spring Tracy Pictures", - "zzz =2007.0 Winter Tracy Pictures", - "zzz =2007.2 Summer Tracy Pictures", - "zzz =2008.0 Winter Tracy Pictures", - "zzz =2008.2 Summer Tracy Pictures", - "zzz =2009.0 Winter Tracy Pictures", - "zzz =2009.2 Summer Tracy Pictures", - "zzz =2009.3 Fall Tracy Pictures", - "zzz =2009.4 Winter Tracy Pictures", - "zzz =2010.0 Winter Tracy Pictures", - "zzz =2010.1 Spring Tracy Pictures", - "zzz =2010.2 Summer Tracy Pictures", - "zzz =2010.3 Fall Tracy Pictures", - "zzz =2011.0 Winter Tracy Pictures", - "zzz =2011.1 Spring Tracy Pictures", - "zzz =2011.2 Summer Tracy Pictures", - "zzz =2011.3 Fall Tracy Pictures", - "zzz =2011.4 Winter Tracy Pictures", - "zzz =2012.0 Winter Tracy Pictures", - "zzz =2012.1 Spring Tracy Pictures", - "zzz =2012.2 Summer Tracy Pictures", - "zzz =2012.3 Fall Tracy Pictures", - "zzz =2012.4 Winter Tracy Pictures", - "zzz =2013.0 Winter Tracy Pictures", - "zzz =2013.1 Spring Tracy Pictures", - "zzz =2013.2 Summer Tracy Pictures", - "zzz =2013.3 Fall Tracy Pictures", - "zzz =2013.4 Winter Tracy Pictures", - "zzz =2014.0 Winter Tracy Pictures", - "zzz =2014.1 Spring Tracy Pictures", - "zzz =2014.2 Summer Tracy Pictures", - "zzz =2014.3 Fall Tracy Pictures", - "zzz =2014.4 Winter Tracy Pictures", - "zzz =2015.0 Winter Tracy Pictures" - ], - "MixedYearRelativePaths": [ - "Edited", - "Phares Slides", - "Rex Memorial", - "Scanned Grandma's Quilt", - "Scanned Pictures Of Kids", - "Scanned Prints", - "Slide in Name Order Originals (622)", - "Slides Pictures" - ], - "IgnoreRelativePaths": [ - "3757 W Whitman 2017", - "501 Playful Meadows 2006", - "501 Playful Meadows 2007", - "501 Playful Meadows 2008", - "501 Playful Meadows 2009", - "501 Playful Meadows 2010", - "501 Playful Meadows 2013", - "501 Playful Meadows 2015", - "6309 Evesham 2003", - "6309 Evesham 2004", - "Crystal's Wedding 2003", - "Danny's Wedding 2009", - "Door images 2019", - "Family Pictures 2006", - "Family Pictures 2007", - "Family Pictures 2011", - "Family Pictures 2013", - "GrandPrix 2004", - "Kids School Pictures 2004", - "Kristy 2002", - "Kristy Parents Wedding 2005", - "Logan Ultrasound 2007", - "Mandy's Dogs 2008", - "Motorcycles 2010", - "Motorcycles 2013", - "Motorcycles 2014", - "Phares Slides", - "Portrait Innovations April 2008", - "Portrait Innovations December 2007", - "Portrait Innovations June 2008", - "Portrait Innovations March 2012", - "The guys house 2000", - "Tracy Pictures 2005", - "Tracy Pictures 2006", - "Tracy Pictures 2007", - "Tracy Pictures 2008", - "Tracy Pictures 2009", - "Tracy Pictures 2010", - "Tracy Pictures 2011", - "Tracy Pictures 2012", - "Tracy Pictures 2013 Jan-July", - "Tracy Pictures 2013 July- Dec", - "Tracy Pictures 2014", - "Tracy Pictures 2015", - "Tracy Took The Kids 2006", - "Tracy's Bday 2012", - "Tracy's Wedding 2002", - "Trip to Colorado 10 2002", - "Trip to Colorado June 2002", - "Tub 2002", - "Vericruz 2011" - ] - } - } -} \ No newline at end of file diff --git a/Tests/appsettings.json b/Tests/appsettings.json deleted file mode 100644 index 2dcb0dc..0000000 --- a/Tests/appsettings.json +++ /dev/null @@ -1,525 +0,0 @@ -{ - "Company": "Mike Phares", - "Linux": {}, - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Log4netProvider": "Information", - "Microsoft.Hosting.Lifetime": "Information" - } - }, - "MaxDegreeOfParallelism": 12, - "Serilog": { - "Using": [ - "Serilog.Sinks.Console", - "Serilog.Sinks.File" - ], - "MinimumLevel": "Debug", - "WriteTo": [ - { - "Name": "Debug", - "Args": { - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" - } - }, - { - "Name": "Console", - "Args": { - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" - } - }, - { - "Name": "File", - "Args": { - "path": "%workingDirectory% - Log/log-.txt", - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}", - "rollingInterval": "Hour" - } - } - ], - "Enrich": [ - "FromLogContext", - "WithMachineName", - "WithThreadId" - ], - "Properties": { - "Application": "Sample" - } - }, - "WorkingDirectoryName": "PharesApps", - "Windows": { - "Configuration": { - "CheckJsonForDistanceResults": false, - "CrossDirectoryMaxItemsInDistanceCollection": 7, - "DateGroup": "2022-08-14", - "DistanceFactor": 8, - "FileNameDirectorySeparator": ".Z.", - "ForceMetadataLastWriteTimeToCreationTime": false, - "ForcePropertyLastWriteTimeToCreationTime": false, - "ForceResizeLastWriteTimeToCreationTime": false, - "LoadOrCreateThenSaveIndex": false, - "LocationConfidenceFactor": 2, - "MappedMaxIndex": 1034720, - "MaxImagesInDirectoryForTopLevelFirstPass": 50, - "MaxItemsInDistanceCollection": 50, - "ModelDirectory": "C:/GitHub/dlib-models", - "ModelName": "Hog", - "NumberOfJitters": 1, - "NumberOfTimesToUpsample": 1, - "OutputExtension": ".jpg", - "OutputQuality": 95, - "OverrideForFaceImages": false, - "OverrideForFaceLandmarkImages": false, - "OverrideForResizeImages": false, - "PaddingLoops": 5, - "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", - "PopulatePropertyId": true, - "PredictorModelName": "Large", - "PropertiesChangedForDistance": false, - "PropertiesChangedForFaces": false, - "PropertiesChangedForIndex": false, - "PropertiesChangedForMetadata": false, - "PropertiesChangedForProperty": false, - "PropertiesChangedForResize": false, - "Reverse": false, - "RootDirectory": "D:/Images", - "SaveFullYearOfRandomFiles": true, - "SaveResizedSubFiles": true, - "SkipSearch": false, - "TestDistanceResults": true, - "WriteBitmapDataBytes": false, - "IgnoreExtensions": [ - ".gif", - ".GIF" - ], - "JuliePhares": [ - "1500-01-16_00", - "1500-01-19_00", - "1500-01-20_00", - "1500-01-21_00", - "1500-01-25_00", - "1500-01-26_00", - "1500-01-27_00", - "1500-02-13_00", - "1500-02-17_00", - "1500-02-24_00", - "1500-02-25_00", - "1500-04-03_00", - "1500-04-06_00", - "1500-04-19_00", - "1500-05-03_00", - "1500-05-18_00", - "1500-05-28_00", - "1500-06-16_00", - "1500-06-26_00", - "1500-06-27_00", - "1500-07-07_00", - "1500-07-16_00", - "1720-09-30_05", - "1500-07-26_00", - "1500-08-03_00", - "1500-08-23_00", - "1500-08-24_00", - "1500-09-16_00", - "1500-09-21_00", - "1500-09-28_00", - "1500-10-14_00", - "1500-11-07_00", - "1500-11-09_00", - "1720-09-28_20", - "1501-01-08_00", - "1501-01-12_00", - "1501-01-13_00", - "1501-01-30_00", - "1501-03-09_00", - "1501-03-14_00", - "1501-03-22_00", - "1501-04-07_00", - "1501-04-10_00", - "1501-04-19_00", - "1501-05-06_00", - "1956-09-19_00", - "2012-09-17_00", - "1998-05-21_00", - "1960-03-01_00", - "1976-03-08_00", - "2007-09-07_00", - "2000-04-07_00", - "1980-01-17_00", - "1958-01-30_00", - "1976-01-05_00", - "1982-05-02_00" - ], - "LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions": [ - "1920 x 1080" - ], - "LoadOrCreateThenSaveDistanceResultsForOutputResolutions": [ - "1920 x 1080" - ], - "LoadOrCreateThenSaveImageFacesResultsForOutputResolutions": [ - "1920 x 1080" - ], - "OutputResolutions": [ - "176 x 176", - "256 x 256", - "353 x 353", - "1024 x 768", - "1920 x 1080" - ], - "PropertyContentCollectionFiles": [], - "SaveFaceLandmarkForOutputResolutions": [ - "176 x 176", - "256 x 256" - ], - "SaveShortcutsForOutputResolutions": [ - "1920 x 1080" - ], - "ValidImageFormatExtensions": [ - ".bmp", - ".BMP", - ".gif", - ".GIF", - ".jpeg", - ".JPEG", - ".jpg", - ".JPG", - ".png", - ".PNG", - ".tiff", - ".TIFF" - ], - "ValidMetadataExtensions": [ - ".3gp", - ".3GP", - ".amr", - ".AMR", - ".avi", - ".AVI", - ".bmp", - ".BMP", - ".gif", - ".GIF", - ".ico", - ".ICO", - ".jpeg", - ".JPEG", - ".jpg", - ".JPG", - ".m4v", - ".M4V", - ".mov", - ".MOV", - ".mp4", - ".MP4", - ".mta", - ".MTA", - ".png", - ".PNG", - ".tiff", - ".TIFF" - ], - "ValidResolutions": [ - "176 x 176", - "256 x 256", - "353 x 353", - "1024 x 768", - "1280 x 720", - "1280 x 800", - "1376 x 768", - "1600 x 1200", - "1920 x 1080", - "2256 x 1496", - "3840 x 2160", - "7680 x 4320" - ], - "VerifyToSeason": [ - ". 2000", - ". 2001", - ". 2002", - ". 2003", - ". 2004", - ". 2005", - ". 2006", - ". 2007", - ". 2008", - ". 2009", - ". 2010", - ". 2011", - ". 2012", - ". 2013", - ". 2014", - ". 2015", - ". 2016", - ". 2017", - ". 2018", - ". 2019", - ". 2020", - ". 2021", - ". 2022", - ". 2023", - ". 2024", - ". 2025", - ". 2026", - ". 2027", - ". 2028", - ". 2029", - "=2000.0 Winter", - "=2002.1 Spring", - "=2002.4 Winter", - "=2003.0 Winter", - "=2003.1 Spring", - "=2003.3 Fall", - "=2003.4 Winter", - "=2004.0 Winter", - "=2005.1 Spring", - "=2005.2 Summer", - "=2005.3 Fall", - "=2005.4 Winter", - "=2006.0 Winter", - "=2006.1 Spring", - "=2006.3 Fall", - "=2007.0 Winter", - "=2007.2 Summer Logan Michael", - "=2007.2 Summer", - "=2007.3 Fall Logan Michael", - "=2007.4 Winter Logan Michael", - "=2008.0 Winter Logan Michael", - "=2008.1 Spring Logan Michael", - "=2008.2 Summer Logan Michael", - "=2008.2 Summer", - "=2008.3 Fall Logan Michael", - "=2009.0 Winter Logan Michael", - "=2009.0 Winter", - "=2009.1 Spring Logan Michael", - "=2009.1 Spring", - "=2009.2 Summer Logan Michael", - "=2009.2 Summer", - "=2009.3 Fall Logan Michael", - "=2009.3 Fall", - "=2009.4 Winter Logan Michael", - "=2009.4 Winter", - "=2010.0 Winter Logan Michael", - "=2010.0 Winter", - "=2010.1 Spring Logan Michael", - "=2010.1 Spring", - "=2010.2 Summer", - "=2010.3 Fall Logan Michael", - "=2010.3 Fall", - "=2010.4 Winter", - "=2011.0 Winter", - "=2011.1 Spring", - "=2011.2 Summer", - "=2011.3 Fall", - "=2011.4 Winter", - "=2012.0 Winter Chelsea 2012", - "=2012.0 Winter Chelsea", - "=2012.0 Winter", - "=2012.1 Spring Chelsea", - "=2012.1 Spring", - "=2012.2 Summer Chelsea", - "=2012.2 Summer", - "=2012.3 Fall Chelsea", - "=2012.3 Fall", - "=2012.4 Winter Chelsea", - "=2012.4 Winter", - "=2013.0 Winter Chelsea 2013", - "=2013.0 Winter Chelsea", - "=2013.0 Winter", - "=2013.1 Spring", - "=2013.2 Summer Chelsea", - "=2013.2 Summer", - "=2013.3 Fall Chelsea", - "=2013.3 Fall", - "=2013.4 Winter", - "=2014.0 Winter", - "=2014.1 Spring", - "=2014.2 Summer", - "=2014.3 Fall", - "=2014.4 Winter", - "=2015.0 Winter", - "=2015.1 Spring", - "=2015.2 Summer", - "=2015.3 Fall", - "=2015.4 Winter", - "=2016.0 Winter", - "=2016.1 Spring", - "=2016.2 Summer", - "=2016.3 Fall", - "=2016.4 Winter", - "=2017.1 Spring", - "=2017.2 Summer", - "=2017.3 Fall", - "=2017.4 Winter", - "=2018.0 Winter", - "=2018.1 Spring", - "=2018.3 Fall", - "=2018.4 Winter", - "=2019.0 Winter", - "=2019.1 Spring", - "=2019.2 Summer", - "=2019.3 Fall", - "=2019.4 Winter", - "=2020.0 Winter", - "=2020.1 Spring", - "=2020.2 Summer", - "=2020.3 Fall", - "=2020.4 Winter", - "=2021.1 Spring", - "=2021.2 Summer", - "=2021.3 Fall", - "=2021.4 Winter", - "=2022.0 Winter", - "=2022.1 Spring", - "Anthem 2015", - "April 2010", - "April 2013", - "December 2006", - "December 2010", - "Fall 2005", - "Fall 2015", - "Fall 2016", - "Fall 2017", - "Fall 2018", - "Fall 2019", - "Fall 2020", - "Fall 2021", - "February 2010", - "January 2015", - "July 2010", - "June 2010", - "Kids 2005", - "March 2013", - "May 2010", - "May 2011", - "May 2013", - "October 2005", - "October 2014", - "Spring 2013", - "Spring 2014", - "Spring 2016", - "Spring 2018", - "Spring 2019", - "Spring 2020", - "Summer 2011", - "Summer 2012", - "Summer 2013", - "Summer 2014", - "Summer 2015", - "Summer 2016", - "Summer 2017", - "Summer 2018", - "Summer 2020", - "Summer 2021", - "Winter 2015", - "Winter 2016", - "Winter 2017", - "Winter 2018", - "Winter 2019-2020", - "Winter 2020", - "zzz =2005.0 Winter Tracy Pictures", - "zzz =2005.1 Spring Tracy Pictures", - "zzz =2005.2 Summer Tracy Pictures", - "zzz =2005.3 Fall Tracy Pictures", - "zzz =2005.4 Winter Tracy Pictures", - "zzz =2006.1 Spring Tracy Pictures", - "zzz =2007.0 Winter Tracy Pictures", - "zzz =2007.2 Summer Tracy Pictures", - "zzz =2008.0 Winter Tracy Pictures", - "zzz =2008.2 Summer Tracy Pictures", - "zzz =2009.0 Winter Tracy Pictures", - "zzz =2009.2 Summer Tracy Pictures", - "zzz =2009.3 Fall Tracy Pictures", - "zzz =2009.4 Winter Tracy Pictures", - "zzz =2010.0 Winter Tracy Pictures", - "zzz =2010.1 Spring Tracy Pictures", - "zzz =2010.2 Summer Tracy Pictures", - "zzz =2010.3 Fall Tracy Pictures", - "zzz =2011.0 Winter Tracy Pictures", - "zzz =2011.1 Spring Tracy Pictures", - "zzz =2011.2 Summer Tracy Pictures", - "zzz =2011.3 Fall Tracy Pictures", - "zzz =2011.4 Winter Tracy Pictures", - "zzz =2012.0 Winter Tracy Pictures", - "zzz =2012.1 Spring Tracy Pictures", - "zzz =2012.2 Summer Tracy Pictures", - "zzz =2012.3 Fall Tracy Pictures", - "zzz =2012.4 Winter Tracy Pictures", - "zzz =2013.0 Winter Tracy Pictures", - "zzz =2013.1 Spring Tracy Pictures", - "zzz =2013.2 Summer Tracy Pictures", - "zzz =2013.3 Fall Tracy Pictures", - "zzz =2013.4 Winter Tracy Pictures", - "zzz =2014.0 Winter Tracy Pictures", - "zzz =2014.1 Spring Tracy Pictures", - "zzz =2014.2 Summer Tracy Pictures", - "zzz =2014.3 Fall Tracy Pictures", - "zzz =2014.4 Winter Tracy Pictures", - "zzz =2015.0 Winter Tracy Pictures" - ], - "MixedYearRelativePaths": [ - "Edited", - "Phares Slides", - "Rex Memorial", - "Scanned Grandma's Quilt", - "Scanned Pictures Of Kids", - "Scanned Prints", - "Slide in Name Order Originals (622)", - "Slides Pictures" - ], - "IgnoreRelativePaths": [ - "3757 W Whitman 2017", - "501 Playful Meadows 2006", - "501 Playful Meadows 2007", - "501 Playful Meadows 2008", - "501 Playful Meadows 2009", - "501 Playful Meadows 2010", - "501 Playful Meadows 2013", - "501 Playful Meadows 2015", - "6309 Evesham 2003", - "6309 Evesham 2004", - "Crystal's Wedding 2003", - "Danny's Wedding 2009", - "Door images 2019", - "Family Pictures 2006", - "Family Pictures 2007", - "Family Pictures 2011", - "Family Pictures 2013", - "GrandPrix 2004", - "Kids School Pictures 2004", - "Kristy 2002", - "Kristy Parents Wedding 2005", - "Logan Ultrasound 2007", - "Mandy's Dogs 2008", - "Motorcycles 2010", - "Motorcycles 2013", - "Motorcycles 2014", - "Phares Slides", - "Portrait Innovations April 2008", - "Portrait Innovations December 2007", - "Portrait Innovations June 2008", - "Portrait Innovations March 2012", - "The guys house 2000", - "Tracy Pictures 2005", - "Tracy Pictures 2006", - "Tracy Pictures 2007", - "Tracy Pictures 2008", - "Tracy Pictures 2009", - "Tracy Pictures 2010", - "Tracy Pictures 2011", - "Tracy Pictures 2012", - "Tracy Pictures 2013 Jan-July", - "Tracy Pictures 2013 July- Dec", - "Tracy Pictures 2014", - "Tracy Pictures 2015", - "Tracy Took The Kids 2006", - "Tracy's Bday 2012", - "Tracy's Wedding 2002", - "Trip to Colorado 10 2002", - "Trip to Colorado June 2002", - "Tub 2002", - "Vericruz 2011" - ] - } - } -} \ No newline at end of file diff --git a/TestsWithFaceRecognitionDotNet/Models/AppSettings.cs b/TestsWithFaceRecognitionDotNet/Models/AppSettings.cs index 246901f..ff0c37b 100644 --- a/TestsWithFaceRecognitionDotNet/Models/AppSettings.cs +++ b/TestsWithFaceRecognitionDotNet/Models/AppSettings.cs @@ -1,7 +1,7 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace View_by_Distance.TestsWithFaceRecognitionDotNet.Models; +namespace View_by_Distance.Tests.Models; public class AppSettings { diff --git a/TestsWithFaceRecognitionDotNet/Models/Binder/AppSettings.cs b/TestsWithFaceRecognitionDotNet/Models/Binder/AppSettings.cs index 534037d..2167e26 100644 --- a/TestsWithFaceRecognitionDotNet/Models/Binder/AppSettings.cs +++ b/TestsWithFaceRecognitionDotNet/Models/Binder/AppSettings.cs @@ -1,7 +1,7 @@ using Microsoft.Extensions.Configuration; using System.Text.Json; -namespace View_by_Distance.TestsWithFaceRecognitionDotNet.Models.Binder; +namespace View_by_Distance.Tests.Models.Binder; public class AppSettings { diff --git a/TestsWithFaceRecognitionDotNet/Models/Binder/Configuration.cs b/TestsWithFaceRecognitionDotNet/Models/Binder/Configuration.cs index 2efa8d0..af47e75 100644 --- a/TestsWithFaceRecognitionDotNet/Models/Binder/Configuration.cs +++ b/TestsWithFaceRecognitionDotNet/Models/Binder/Configuration.cs @@ -1,14 +1,19 @@ +using Microsoft.Extensions.Configuration; +using Phares.Shared; using System.ComponentModel.DataAnnotations; using System.Text.Json; -namespace View_by_Distance.TestsWithFaceRecognitionDotNet.Models.Binder; +namespace View_by_Distance.Tests.Models.Binder; public class Configuration { +#nullable disable + [Display(Name = "Check Json For Distance Results"), Required] public bool? CheckJsonForDistanceResults { get; set; } [Display(Name = "CrossDirectory Max Items In Distance Collection"), Required] public int? CrossDirectoryMaxItemsInDistanceCollection { get; set; } [Display(Name = "Distance Factor"), Required] public int? DistanceFactor { get; set; } + [Display(Name = "Force Face Last Write Time to Creation Time"), Required] public bool? ForceFaceLastWriteTimeToCreationTime { get; set; } [Display(Name = "Force Metadata Last Write Time to Creation Time"), Required] public bool? ForceMetadataLastWriteTimeToCreationTime { get; set; } [Display(Name = "Force Resize Last Write Time to Creation Time"), Required] public bool? ForceResizeLastWriteTimeToCreationTime { get; set; } [Display(Name = "Ignore Extensions"), Required] public string[] IgnoreExtensions { get; set; } @@ -39,7 +44,7 @@ public class Configuration [Display(Name = "Properties Changed For Index"), Required] public bool? PropertiesChangedForIndex { get; set; } [Display(Name = "Properties Changed For Metadata"), Required] public bool? PropertiesChangedForMetadata { get; set; } [Display(Name = "Properties Changed For Resize"), Required] public bool? PropertiesChangedForResize { get; set; } - [Display(Name = "Property Configuration"), Required] public Property.Models.Configuration? PropertyConfiguration { get; set; } + [Display(Name = "Property Configuration"), Required] public Property.Models.Configuration PropertyConfiguration { get; set; } [Display(Name = "Reverse"), Required] public bool? Reverse { get; set; } [Display(Name = "Save Face Landmark For Output Resolutions"), Required] public string[] SaveFaceLandmarkForOutputResolutions { get; set; } [Display(Name = "Save Full Year Of Random Files"), Required] public bool? SaveFullYearOfRandomFiles { get; set; } @@ -49,50 +54,7 @@ public class Configuration [Display(Name = "Test Distance Results"), Required] public bool? TestDistanceResults { get; set; } [Display(Name = "Valid Resolutions"), Required] public string[] ValidResolutions { get; set; } - public Configuration() - { - CheckJsonForDistanceResults = null; - CrossDirectoryMaxItemsInDistanceCollection = null; - DistanceFactor = null; - ForceMetadataLastWriteTimeToCreationTime = null; - ForceResizeLastWriteTimeToCreationTime = null; - IgnoreExtensions = Array.Empty(); - IgnoreRelativePaths = Array.Empty(); - JuliePhares = Array.Empty(); - LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions = Array.Empty(); - LoadOrCreateThenSaveDistanceResultsForOutputResolutions = Array.Empty(); - LoadOrCreateThenSaveImageFacesResultsForOutputResolutions = Array.Empty(); - LoadOrCreateThenSaveIndex = null; - LocationConfidenceFactor = null; - MappedMaxIndex = null; - MaxItemsInDistanceCollection = null; - MixedYearRelativePaths = Array.Empty(); - ModelDirectory = string.Empty; - ModelName = string.Empty; - NumberOfJitters = null; - NumberOfTimesToUpsample = null; - OutputExtension = string.Empty; - OutputQuality = null; - OutputResolutions = Array.Empty(); - OverrideForFaceImages = null; - OverrideForFaceLandmarkImages = null; - OverrideForResizeImages = null; - PaddingLoops = null; - PredictorModelName = string.Empty; - PropertiesChangedForDistance = null; - PropertiesChangedForFaces = null; - PropertiesChangedForIndex = null; - PropertiesChangedForMetadata = null; - PropertiesChangedForResize = null; - Reverse = null; - SaveFaceLandmarkForOutputResolutions = Array.Empty(); - SaveFullYearOfRandomFiles = null; - SaveResizedSubfiles = null; - SaveShortcutsForOutputResolutions = Array.Empty(); - SkipSearch = null; - TestDistanceResults = null; - ValidResolutions = Array.Empty(); - } +#nullable restore public override string ToString() { @@ -100,4 +62,146 @@ public class Configuration return result; } + private static Models.Configuration Get(Configuration configuration) + { + Models.Configuration result; + if (configuration.CheckJsonForDistanceResults is null) + throw new NullReferenceException(nameof(configuration.CheckJsonForDistanceResults)); + if (configuration.CrossDirectoryMaxItemsInDistanceCollection is null) + throw new NullReferenceException(nameof(configuration.CrossDirectoryMaxItemsInDistanceCollection)); + if (configuration.DistanceFactor is null) + throw new NullReferenceException(nameof(configuration.DistanceFactor)); + if (configuration.ForceFaceLastWriteTimeToCreationTime is null) + throw new NullReferenceException(nameof(configuration.ForceFaceLastWriteTimeToCreationTime)); + if (configuration.ForceMetadataLastWriteTimeToCreationTime is null) + throw new NullReferenceException(nameof(configuration.ForceMetadataLastWriteTimeToCreationTime)); + if (configuration.ForceResizeLastWriteTimeToCreationTime is null) + throw new NullReferenceException(nameof(configuration.ForceResizeLastWriteTimeToCreationTime)); + if (configuration.IgnoreExtensions is null) + throw new NullReferenceException(nameof(configuration.IgnoreExtensions)); + if (configuration.IgnoreRelativePaths is null) + throw new NullReferenceException(nameof(configuration.IgnoreRelativePaths)); + if (configuration.LoadOrCreateThenSaveIndex is null) + throw new NullReferenceException(nameof(configuration.LoadOrCreateThenSaveIndex)); + if (configuration.LocationConfidenceFactor is null) + throw new NullReferenceException(nameof(configuration.LocationConfidenceFactor)); + if (configuration.MaxItemsInDistanceCollection is null) + throw new NullReferenceException(nameof(configuration.MaxItemsInDistanceCollection)); + if (configuration.MixedYearRelativePaths is null) + throw new NullReferenceException(nameof(configuration.MixedYearRelativePaths)); + if (configuration.NumberOfJitters is null) + throw new NullReferenceException(nameof(configuration.NumberOfJitters)); + if (configuration.NumberOfTimesToUpsample is null) + throw new NullReferenceException(nameof(configuration.NumberOfTimesToUpsample)); + if (configuration.OutputQuality is null) + throw new NullReferenceException(nameof(configuration.OutputQuality)); + if (configuration.OutputResolutions is null) + throw new NullReferenceException(nameof(configuration.OutputResolutions)); + if (configuration.OverrideForFaceImages is null) + throw new NullReferenceException(nameof(configuration.OverrideForFaceImages)); + if (configuration.OverrideForFaceLandmarkImages is null) + throw new NullReferenceException(nameof(configuration.OverrideForFaceLandmarkImages)); + if (configuration.OverrideForResizeImages is null) + throw new NullReferenceException(nameof(configuration.OverrideForResizeImages)); + if (configuration.PaddingLoops is null) + throw new NullReferenceException(nameof(configuration.PaddingLoops)); + if (configuration.PropertiesChangedForDistance is null) + throw new NullReferenceException(nameof(configuration.PropertiesChangedForDistance)); + if (configuration.PropertiesChangedForFaces is null) + throw new NullReferenceException(nameof(configuration.PropertiesChangedForFaces)); + if (configuration.PropertiesChangedForIndex is null) + throw new NullReferenceException(nameof(configuration.PropertiesChangedForIndex)); + if (configuration.PropertiesChangedForMetadata is null) + throw new NullReferenceException(nameof(configuration.PropertiesChangedForMetadata)); + if (configuration.PropertiesChangedForResize is null) + throw new NullReferenceException(nameof(configuration.PropertiesChangedForResize)); + if (configuration.Reverse is null) + throw new NullReferenceException(nameof(configuration.Reverse)); + if (configuration.SaveFaceLandmarkForOutputResolutions is null) + throw new NullReferenceException(nameof(configuration.SaveFaceLandmarkForOutputResolutions)); + if (configuration.SaveFullYearOfRandomFiles is null) + throw new NullReferenceException(nameof(configuration.SaveFullYearOfRandomFiles)); + if (configuration.SaveResizedSubfiles is null) + throw new NullReferenceException(nameof(configuration.SaveResizedSubfiles)); + if (configuration.SkipSearch is null) + throw new NullReferenceException(nameof(configuration.SkipSearch)); + if (configuration.TestDistanceResults is null) + throw new NullReferenceException(nameof(configuration.TestDistanceResults)); + if (configuration.ValidResolutions is null) + throw new NullReferenceException(nameof(configuration.ValidResolutions)); + if (configuration.LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions is null) + configuration.LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions = Array.Empty(); + if (configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions is null) + configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions = Array.Empty(); + if (configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions is null) + configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions = Array.Empty(); + if (configuration.SaveFaceLandmarkForOutputResolutions is null) + configuration.SaveFaceLandmarkForOutputResolutions = Array.Empty(); + if (configuration.SaveShortcutsForOutputResolutions is null) + configuration.SaveShortcutsForOutputResolutions = Array.Empty(); + result = new(configuration.PropertyConfiguration, + configuration.CheckJsonForDistanceResults.Value, + configuration.CrossDirectoryMaxItemsInDistanceCollection.Value, + configuration.DistanceFactor.Value, + configuration.ForceFaceLastWriteTimeToCreationTime.Value, + configuration.ForceMetadataLastWriteTimeToCreationTime.Value, + configuration.ForceResizeLastWriteTimeToCreationTime.Value, + configuration.IgnoreExtensions, + configuration.IgnoreRelativePaths, + configuration.JuliePhares, + configuration.LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions, + configuration.LoadOrCreateThenSaveDistanceResultsForOutputResolutions, + configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions, + configuration.LoadOrCreateThenSaveIndex.Value, + configuration.LocationConfidenceFactor.Value, + configuration.MappedMaxIndex, + configuration.MaxItemsInDistanceCollection.Value, + configuration.MixedYearRelativePaths, + configuration.ModelDirectory, + configuration.ModelName, + configuration.NumberOfJitters.Value, + configuration.NumberOfTimesToUpsample.Value, + configuration.OutputExtension, + configuration.OutputQuality.Value, + configuration.OutputResolutions, + configuration.OverrideForFaceImages.Value, + configuration.OverrideForFaceLandmarkImages.Value, + configuration.OverrideForResizeImages.Value, + configuration.PaddingLoops.Value, + configuration.PredictorModelName, + configuration.PropertiesChangedForDistance.Value, + configuration.PropertiesChangedForFaces.Value, + configuration.PropertiesChangedForIndex.Value, + configuration.PropertiesChangedForMetadata.Value, + configuration.PropertiesChangedForResize.Value, + configuration.Reverse.Value, + configuration.SaveFaceLandmarkForOutputResolutions, + configuration.SaveFullYearOfRandomFiles.Value, + configuration.SaveResizedSubfiles.Value, + configuration.SaveShortcutsForOutputResolutions, + configuration.SkipSearch.Value, + configuration.TestDistanceResults.Value, + configuration.ValidResolutions); + return result; + } + + public static Models.Configuration Get(IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, Property.Models.Configuration propertyConfiguration) + { + Models.Configuration result; + Configuration configuration; + if (isEnvironment is null) + configuration = configurationRoot.Get(); + else + { + string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); + string section = string.Concat(environmentName, ":", nameof(Configuration)); + IConfigurationSection configurationSection = configurationRoot.GetSection(section); + configuration = configurationSection.Get(); + } + result = Get(configuration); + result.Set(propertyConfiguration); + result.Update(); + return result; + } + } \ No newline at end of file diff --git a/TestsWithFaceRecognitionDotNet/Models/Configuration.cs b/TestsWithFaceRecognitionDotNet/Models/Configuration.cs index 1ded4df..a5cb689 100644 --- a/TestsWithFaceRecognitionDotNet/Models/Configuration.cs +++ b/TestsWithFaceRecognitionDotNet/Models/Configuration.cs @@ -1,141 +1,103 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace View_by_Distance.TestsWithFaceRecognitionDotNet.Models; +namespace View_by_Distance.Tests.Models; public class Configuration { - protected readonly bool? _CheckJsonForDistanceResults; - protected readonly int? _CrossDirectoryMaxItemsInDistanceCollection; - protected readonly int? _DistanceFactor; - protected readonly bool? _ForceMetadataLastWriteTimeToCreationTime; - protected readonly bool? _ForceResizeLastWriteTimeToCreationTime; - protected readonly string[] _IgnoreExtensions; - protected readonly string[] _IgnoreRelativePaths; - protected readonly string[] _JuliePhares; - protected readonly string[] _LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions; - protected readonly string[] _LoadOrCreateThenSaveDistanceResultsForOutputResolutions; - protected readonly string[] _LoadOrCreateThenSaveImageFacesResultsForOutputResolutions; - protected readonly bool? _LoadOrCreateThenSaveIndex; - protected readonly int? _LocationConfidenceFactor; - protected readonly int? _MappedMaxIndex; - protected readonly int? _MaxItemsInDistanceCollection; - protected readonly string[] _MixedYearRelativePaths; - protected readonly string _ModelDirectory; - protected readonly string _ModelName; - protected readonly int? _NumberOfJitters; - protected readonly int? _NumberOfTimesToUpsample; - protected readonly string _OutputExtension; - protected readonly int? _OutputQuality; - protected readonly string[] _OutputResolutions; - protected readonly bool? _OverrideForFaceImages; - protected readonly bool? _OverrideForFaceLandmarkImages; - protected readonly bool? _OverrideForResizeImages; - protected readonly int? _PaddingLoops; - protected readonly string _PredictorModelName; - protected readonly bool? _PropertiesChangedForDistance; - protected readonly bool? _PropertiesChangedForFaces; - protected readonly bool? _PropertiesChangedForIndex; - protected readonly bool? _PropertiesChangedForMetadata; - protected readonly bool? _PropertiesChangedForResize; - protected Property.Models.Configuration? _PropertyConfiguration; - protected readonly bool? _Reverse; - protected readonly string[] _SaveFaceLandmarkForOutputResolutions; - protected readonly bool? _SaveFullYearOfRandomFiles; - protected readonly bool? _SaveResizedSubfiles; - protected readonly string[] _SaveShortcutsForOutputResolutions; - protected readonly bool? _SkipSearch; - protected readonly bool? _TestDistanceResults; - protected readonly string[] _ValidResolutions; - public bool? CheckJsonForDistanceResults => _CheckJsonForDistanceResults; - public int? CrossDirectoryMaxItemsInDistanceCollection => _CrossDirectoryMaxItemsInDistanceCollection; - public int? DistanceFactor => _DistanceFactor; - public bool? ForceMetadataLastWriteTimeToCreationTime => _ForceMetadataLastWriteTimeToCreationTime; - public bool? ForceResizeLastWriteTimeToCreationTime => _ForceResizeLastWriteTimeToCreationTime; - public string[] IgnoreExtensions => _IgnoreExtensions; - public string[] IgnoreRelativePaths => _IgnoreRelativePaths; - public string[] JuliePhares => _JuliePhares; - public string[] LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions => _LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions; - public string[] LoadOrCreateThenSaveDistanceResultsForOutputResolutions => _LoadOrCreateThenSaveDistanceResultsForOutputResolutions; - public string[] LoadOrCreateThenSaveImageFacesResultsForOutputResolutions => _LoadOrCreateThenSaveImageFacesResultsForOutputResolutions; - public bool? LoadOrCreateThenSaveIndex => _LoadOrCreateThenSaveIndex; - public int? LocationConfidenceFactor => _LocationConfidenceFactor; - public int? MappedMaxIndex => _MappedMaxIndex; - public int? MaxItemsInDistanceCollection => _MaxItemsInDistanceCollection; - public string[] MixedYearRelativePaths => _MixedYearRelativePaths; - public string ModelDirectory => _ModelDirectory; - public string ModelName => _ModelName; - public int? NumberOfJitters => _NumberOfJitters; - public int? NumberOfTimesToUpsample => _NumberOfTimesToUpsample; - public string OutputExtension => _OutputExtension; - public int? OutputQuality => _OutputQuality; - public string[] OutputResolutions => _OutputResolutions; - public bool? OverrideForFaceImages => _OverrideForFaceImages; - public bool? OverrideForFaceLandmarkImages => _OverrideForFaceLandmarkImages; - public bool? OverrideForResizeImages => _OverrideForResizeImages; - public int? PaddingLoops => _PaddingLoops; - public string PredictorModelName => _PredictorModelName; - public bool? PropertiesChangedForDistance => _PropertiesChangedForDistance; - public bool? PropertiesChangedForFaces => _PropertiesChangedForFaces; - public bool? PropertiesChangedForIndex => _PropertiesChangedForIndex; - public bool? PropertiesChangedForMetadata => _PropertiesChangedForMetadata; - public bool? PropertiesChangedForResize => _PropertiesChangedForResize; - public Property.Models.Configuration? PropertyConfiguration => _PropertyConfiguration; - public bool? Reverse => _Reverse; - public string[] SaveFaceLandmarkForOutputResolutions => _SaveFaceLandmarkForOutputResolutions; - public bool? SaveFullYearOfRandomFiles => _SaveFullYearOfRandomFiles; - public bool? SaveResizedSubfiles => _SaveResizedSubfiles; - public string[] SaveShortcutsForOutputResolutions => _SaveShortcutsForOutputResolutions; - public bool? SkipSearch => _SkipSearch; - public bool? TestDistanceResults => _TestDistanceResults; - public string[] ValidResolutions => _ValidResolutions; + protected Property.Models.Configuration _PropertyConfiguration; + public Property.Models.Configuration PropertyConfiguration => _PropertyConfiguration; + + public bool CheckJsonForDistanceResults { init; get; } + public int CrossDirectoryMaxItemsInDistanceCollection { init; get; } + public int DistanceFactor { init; get; } + public bool ForceFaceLastWriteTimeToCreationTime { init; get; } + public bool ForceMetadataLastWriteTimeToCreationTime { init; get; } + public bool ForceResizeLastWriteTimeToCreationTime { init; get; } + public string[] IgnoreExtensions { init; get; } + public string[] IgnoreRelativePaths { init; get; } + public string[] JuliePhares { init; get; } + public string[] LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions { init; get; } + public string[] LoadOrCreateThenSaveDistanceResultsForOutputResolutions { init; get; } + public string[] LoadOrCreateThenSaveImageFacesResultsForOutputResolutions { init; get; } + public bool LoadOrCreateThenSaveIndex { init; get; } + public int LocationConfidenceFactor { init; get; } + public int? MappedMaxIndex { init; get; } + public int MaxItemsInDistanceCollection { init; get; } + public string[] MixedYearRelativePaths { init; get; } + public string ModelDirectory { init; get; } + public string ModelName { init; get; } + public int NumberOfJitters { init; get; } + public int NumberOfTimesToUpsample { init; get; } + public string OutputExtension { init; get; } + public int OutputQuality { init; get; } + public string[] OutputResolutions { init; get; } + public bool OverrideForFaceImages { init; get; } + public bool OverrideForFaceLandmarkImages { init; get; } + public bool OverrideForResizeImages { init; get; } + public int PaddingLoops { init; get; } + public string PredictorModelName { init; get; } + public bool PropertiesChangedForDistance { init; get; } + public bool PropertiesChangedForFaces { init; get; } + public bool PropertiesChangedForIndex { init; get; } + public bool PropertiesChangedForMetadata { init; get; } + public bool PropertiesChangedForResize { init; get; } + public bool Reverse { init; get; } + public string[] SaveFaceLandmarkForOutputResolutions { init; get; } + public bool SaveFullYearOfRandomFiles { init; get; } + public bool SaveResizedSubfiles { init; get; } + public string[] SaveShortcutsForOutputResolutions { init; get; } + public bool SkipSearch { init; get; } + public bool TestDistanceResults { init; get; } + public string[] ValidResolutions { init; get; } [JsonConstructor] - public Configuration(bool? checkJsonForDistanceResults, int? crossDirectoryMaxItemsInDistanceCollection, int? distanceFactor, bool? forceMetadataLastWriteTimeToCreationTime, bool? forceResizeLastWriteTimeToCreationTime, string[] ignoreExtensions, string[] ignoreRelativePaths, string[] juliePhares, string[] loadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions, string[] loadOrCreateThenSaveDistanceResultsForOutputResolutions, string[] loadOrCreateThenSaveImageFacesResultsForOutputResolutions, bool? loadOrCreateThenSaveIndex, int? locationConfidenceFactor, int? mappedMaxIndex, int? maxItemsInDistanceCollection, string[] mixedYearRelativePaths, string modelDirectory, string modelName, int? numberOfJitters, int? numberOfTimesToUpsample, string outputExtension, int? outputQuality, string[] outputResolutions, bool? overrideForFaceImages, bool? overrideForFaceLandmarkImages, bool? overrideForResizeImages, int? paddingLoops, string predictorModelName, bool? propertiesChangedForDistance, bool? propertiesChangedForFaces, bool? propertiesChangedForIndex, bool? propertiesChangedForMetadata, bool? propertiesChangedForResize, Property.Models.Configuration? propertyConfiguration, bool? reverse, string[] saveFaceLandmarkForOutputResolutions, bool? saveFullYearOfRandomFiles, bool? saveResizedSubfiles, string[] saveShortcutsForOutputResolutions, bool? skipSearch, bool? testDistanceResults, string[] validResolutions) + public Configuration(Property.Models.Configuration propertyConfiguration, bool checkJsonForDistanceResults, int crossDirectoryMaxItemsInDistanceCollection, int distanceFactor, bool forceFaceLastWriteTimeToCreationTime, bool forceMetadataLastWriteTimeToCreationTime, bool forceResizeLastWriteTimeToCreationTime, string[] ignoreExtensions, string[] ignoreRelativePaths, string[] juliePhares, string[] loadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions, string[] loadOrCreateThenSaveDistanceResultsForOutputResolutions, string[] loadOrCreateThenSaveImageFacesResultsForOutputResolutions, bool loadOrCreateThenSaveIndex, int locationConfidenceFactor, int? mappedMaxIndex, int maxItemsInDistanceCollection, string[] mixedYearRelativePaths, string modelDirectory, string modelName, int numberOfJitters, int numberOfTimesToUpsample, string outputExtension, int outputQuality, string[] outputResolutions, bool overrideForFaceImages, bool overrideForFaceLandmarkImages, bool overrideForResizeImages, int paddingLoops, string predictorModelName, bool propertiesChangedForDistance, bool propertiesChangedForFaces, bool propertiesChangedForIndex, bool propertiesChangedForMetadata, bool propertiesChangedForResize, bool reverse, string[] saveFaceLandmarkForOutputResolutions, bool saveFullYearOfRandomFiles, bool saveResizedSubfiles, string[] saveShortcutsForOutputResolutions, bool skipSearch, bool testDistanceResults, string[] validResolutions) { - _CheckJsonForDistanceResults = checkJsonForDistanceResults; - _CrossDirectoryMaxItemsInDistanceCollection = crossDirectoryMaxItemsInDistanceCollection; - _DistanceFactor = distanceFactor; - _ForceMetadataLastWriteTimeToCreationTime = forceMetadataLastWriteTimeToCreationTime; - _ForceResizeLastWriteTimeToCreationTime = forceResizeLastWriteTimeToCreationTime; - _IgnoreExtensions = ignoreExtensions; - _IgnoreRelativePaths = ignoreRelativePaths; - _JuliePhares = juliePhares; - _LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions = loadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions; - _LoadOrCreateThenSaveDistanceResultsForOutputResolutions = loadOrCreateThenSaveDistanceResultsForOutputResolutions; - _LoadOrCreateThenSaveImageFacesResultsForOutputResolutions = loadOrCreateThenSaveImageFacesResultsForOutputResolutions; - _LoadOrCreateThenSaveIndex = loadOrCreateThenSaveIndex; - _LocationConfidenceFactor = locationConfidenceFactor; - _MappedMaxIndex = mappedMaxIndex; - _MaxItemsInDistanceCollection = maxItemsInDistanceCollection; - _MixedYearRelativePaths = mixedYearRelativePaths; - _ModelDirectory = modelDirectory; - _ModelName = modelName; - _NumberOfJitters = numberOfJitters; - _NumberOfTimesToUpsample = numberOfTimesToUpsample; - _OutputExtension = outputExtension; - _OutputQuality = outputQuality; - _OutputResolutions = outputResolutions; - _OverrideForFaceImages = overrideForFaceImages; - _OverrideForFaceLandmarkImages = overrideForFaceLandmarkImages; - _OverrideForResizeImages = overrideForResizeImages; - _PaddingLoops = paddingLoops; - _PredictorModelName = predictorModelName; - _PropertiesChangedForDistance = propertiesChangedForDistance; - _PropertiesChangedForFaces = propertiesChangedForFaces; - _PropertiesChangedForIndex = propertiesChangedForIndex; - _PropertiesChangedForMetadata = propertiesChangedForMetadata; - _PropertiesChangedForResize = propertiesChangedForResize; _PropertyConfiguration = propertyConfiguration; - _Reverse = reverse; - _SaveFaceLandmarkForOutputResolutions = saveFaceLandmarkForOutputResolutions; - _SaveFullYearOfRandomFiles = saveFullYearOfRandomFiles; - _SaveResizedSubfiles = saveResizedSubfiles; - _SaveShortcutsForOutputResolutions = saveShortcutsForOutputResolutions; - _SkipSearch = skipSearch; - _TestDistanceResults = testDistanceResults; - _ValidResolutions = validResolutions; + CheckJsonForDistanceResults = checkJsonForDistanceResults; + CrossDirectoryMaxItemsInDistanceCollection = crossDirectoryMaxItemsInDistanceCollection; + DistanceFactor = distanceFactor; + ForceFaceLastWriteTimeToCreationTime = forceFaceLastWriteTimeToCreationTime; + ForceMetadataLastWriteTimeToCreationTime = forceMetadataLastWriteTimeToCreationTime; + ForceResizeLastWriteTimeToCreationTime = forceResizeLastWriteTimeToCreationTime; + IgnoreExtensions = ignoreExtensions; + IgnoreRelativePaths = ignoreRelativePaths; + JuliePhares = juliePhares; + LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions = loadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions; + LoadOrCreateThenSaveDistanceResultsForOutputResolutions = loadOrCreateThenSaveDistanceResultsForOutputResolutions; + LoadOrCreateThenSaveImageFacesResultsForOutputResolutions = loadOrCreateThenSaveImageFacesResultsForOutputResolutions; + LoadOrCreateThenSaveIndex = loadOrCreateThenSaveIndex; + LocationConfidenceFactor = locationConfidenceFactor; + MappedMaxIndex = mappedMaxIndex; + MaxItemsInDistanceCollection = maxItemsInDistanceCollection; + MixedYearRelativePaths = mixedYearRelativePaths; + ModelDirectory = modelDirectory; + ModelName = modelName; + NumberOfJitters = numberOfJitters; + NumberOfTimesToUpsample = numberOfTimesToUpsample; + OutputExtension = outputExtension; + OutputQuality = outputQuality; + OutputResolutions = outputResolutions; + OverrideForFaceImages = overrideForFaceImages; + OverrideForFaceLandmarkImages = overrideForFaceLandmarkImages; + OverrideForResizeImages = overrideForResizeImages; + PaddingLoops = paddingLoops; + PredictorModelName = predictorModelName; + PropertiesChangedForDistance = propertiesChangedForDistance; + PropertiesChangedForFaces = propertiesChangedForFaces; + PropertiesChangedForIndex = propertiesChangedForIndex; + PropertiesChangedForMetadata = propertiesChangedForMetadata; + PropertiesChangedForResize = propertiesChangedForResize; + Reverse = reverse; + SaveFaceLandmarkForOutputResolutions = saveFaceLandmarkForOutputResolutions; + SaveFullYearOfRandomFiles = saveFullYearOfRandomFiles; + SaveResizedSubfiles = saveResizedSubfiles; + SaveShortcutsForOutputResolutions = saveShortcutsForOutputResolutions; + SkipSearch = skipSearch; + TestDistanceResults = testDistanceResults; + ValidResolutions = validResolutions; } public override string ToString() @@ -146,6 +108,6 @@ public class Configuration public void Set(Property.Models.Configuration configuration) => _PropertyConfiguration = configuration; - public void Update() => _PropertyConfiguration?.Update(); + public void Update() => _PropertyConfiguration.Update(); } \ No newline at end of file diff --git a/TestsWithFaceRecognitionDotNet/Models/Stateless/Configuration.cs b/TestsWithFaceRecognitionDotNet/Models/Stateless/Configuration.cs deleted file mode 100644 index 6fa49df..0000000 --- a/TestsWithFaceRecognitionDotNet/Models/Stateless/Configuration.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Microsoft.Extensions.Configuration; -using Phares.Shared; -using System.Text.Json; - -namespace View_by_Distance.TestsWithFaceRecognitionDotNet.Models.Stateless; - -public abstract class Configuration -{ - - public static Models.Configuration Get(IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, string workingDirectory, Property.Models.Configuration propertyConfiguration) - { - Models.Configuration? result; - string environmentName = IsEnvironment.GetEnvironmentName(isEnvironment); - string section = string.Concat(environmentName, ":", nameof(Binder.Configuration)); - IConfigurationSection configurationSection = configurationRoot.GetSection(section); - Binder.Configuration configuration = configurationSection.Get(); - string json = JsonSerializer.Serialize(configuration, new JsonSerializerOptions() { WriteIndented = true }); - result = JsonSerializer.Deserialize(json); - if (result is null) - throw new Exception(json); - string jsonThis = result.ToString(); - result.Set(propertyConfiguration); - result.Update(); - if (jsonThis != json) - { - int? check = null; - int min = new int[] { json.Length, jsonThis.Length }.Min(); - for (int i = 0; i < min; i++) - { - if (json[i] == jsonThis[i]) - continue; - check = i; - break; - } - if (check is null) - throw new Exception(); - string a = json[..check.Value].Split(',')[^1]; - string b = json[check.Value..].Split(',')[0]; - throw new Exception($"{a}{b}"); - } - return result; - } - -} \ No newline at end of file diff --git a/TestsWithFaceRecognitionDotNet/TestsWithFaceRecognitionDotNet.csproj b/TestsWithFaceRecognitionDotNet/TestsWithFaceRecognitionDotNet.csproj index dde47fe..f89b138 100644 --- a/TestsWithFaceRecognitionDotNet/TestsWithFaceRecognitionDotNet.csproj +++ b/TestsWithFaceRecognitionDotNet/TestsWithFaceRecognitionDotNet.csproj @@ -48,10 +48,13 @@ - + Always - + + Always + + Always diff --git a/TestsWithFaceRecognitionDotNet/UnitTestExample.cs b/TestsWithFaceRecognitionDotNet/UnitTestExample.cs index 7533929..ca752f0 100644 --- a/TestsWithFaceRecognitionDotNet/UnitTestExample.cs +++ b/TestsWithFaceRecognitionDotNet/UnitTestExample.cs @@ -5,9 +5,9 @@ using Serilog; using System.Diagnostics; using System.Reflection; using View_by_Distance.Shared.Models.Stateless.Methods; -using View_by_Distance.TestsWithFaceRecognitionDotNet.Models; +using View_by_Distance.Tests.Models; -namespace View_by_Distance.TestsWithFaceRecognitionDotNet; +namespace View_by_Distance.Tests; [TestClass] public class UnitTestExample @@ -44,8 +44,8 @@ public class UnitTestExample _ = ConfigurationLoggerConfigurationExtensions.Configuration(loggerConfiguration.ReadFrom, configurationRoot); Log.Logger = loggerConfiguration.CreateLogger(); logger = Log.ForContext(); - propertyConfiguration = Property.Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory); - configuration = Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory, propertyConfiguration); + propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot); + configuration = Models.Binder.Configuration.Get(isEnvironment, configurationRoot, propertyConfiguration); logger.Information("Complete"); _Logger = logger; _AppSettings = appSettings; diff --git a/TestsWithFaceRecognitionDotNet/UnitTestFace.cs b/TestsWithFaceRecognitionDotNet/UnitTestFace.cs index 060ba98..cc4149f 100644 --- a/TestsWithFaceRecognitionDotNet/UnitTestFace.cs +++ b/TestsWithFaceRecognitionDotNet/UnitTestFace.cs @@ -11,9 +11,9 @@ using View_by_Distance.Resize.Models; using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Stateless; using View_by_Distance.Shared.Models.Stateless.Methods; -using View_by_Distance.TestsWithFaceRecognitionDotNet.Models; +using View_by_Distance.Tests.Models; -namespace View_by_Distance.TestsWithFaceRecognitionDotNet; +namespace View_by_Distance.Tests; [TestClass] public class UnitTestFace @@ -50,8 +50,8 @@ public class UnitTestFace _ = ConfigurationLoggerConfigurationExtensions.Configuration(loggerConfiguration.ReadFrom, configurationRoot); Log.Logger = loggerConfiguration.CreateLogger(); logger = Log.ForContext(); - propertyConfiguration = Property.Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory); - configuration = Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory, propertyConfiguration); + propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot); + configuration = Models.Binder.Configuration.Get(isEnvironment, configurationRoot, propertyConfiguration); logger.Information("Complete"); _Logger = logger; _AppSettings = appSettings; @@ -74,12 +74,12 @@ public class UnitTestFace Assert.IsFalse(_PropertyConfiguration is null); } - private Property.Models.PropertyLogic GetPropertyLogic(bool reverse, Model? model, PredictorModel? predictorModel) + private Property.Models.A_Property GetPropertyLogic(bool reverse, Model? model, PredictorModel? predictorModel) { - Property.Models.PropertyLogic result; + Property.Models.A_Property result; if (_Configuration?.PropertyConfiguration is null) throw new NullReferenceException(nameof(_Configuration.PropertyConfiguration)); - result = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, reverse, model, predictorModel); + result = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Configuration.OutputExtension, reverse, model, predictorModel); return result; } @@ -124,42 +124,11 @@ public class UnitTestFace return result; } - [TestMethod] - public void TestGetPixelPercentage() - { - int normalizedPixelPercentage; - int left, top, right, bottom, width, height; - left = 1; - top = 1; - right = 10; - bottom = 10; - width = 100; - height = 100; - normalizedPixelPercentage = Location.GetNormalizedPixelPercentage(bottom, height, left, right, top, width); - Assert.IsTrue(normalizedPixelPercentage == 0505); - left = 50; - top = 50; - right = 60; - bottom = 60; - width = 100; - height = 100; - normalizedPixelPercentage = Location.GetNormalizedPixelPercentage(bottom, height, left, right, top, width); - Assert.IsTrue(normalizedPixelPercentage == 5555); - left = 20; - top = 40; - right = 60; - bottom = 80; - width = 100; - height = 100; - normalizedPixelPercentage = Location.GetNormalizedPixelPercentage(bottom, height, left, right, top, width); - Assert.IsTrue(normalizedPixelPercentage == 6040); - } - [TestMethod] public void TestMethodFace() { - string sourceFileName = "IMG_0067.jpg"; - string sourceDirectoryName = "Mackenzie Prom 2017"; + // string sourceFileName = "IMG_0067.jpg"; + // string sourceDirectoryName = "Mackenzie Prom 2017"; // string sourceFileName = "Fall 2005 (113).jpg"; // string sourceDirectoryName = "=2005.3 Fall"; // string sourceFileName = "DSCN0534.jpg"; @@ -168,38 +137,24 @@ public class UnitTestFace // string sourceDirectoryName = "Disneyland 2014"; // string sourceFileName = "Logan Michael Sept 08 (193).jpg"; // string sourceDirectoryName = "=2008.2 Summer Logan Michael"; - if (_Configuration.ForceMetadataLastWriteTimeToCreationTime is null) - throw new NullReferenceException(nameof(_Configuration.ForceMetadataLastWriteTimeToCreationTime)); - if (_Configuration.ForceResizeLastWriteTimeToCreationTime is null) - throw new NullReferenceException(nameof(_Configuration.ForceResizeLastWriteTimeToCreationTime)); - if (_Configuration.OutputQuality is null) - throw new NullReferenceException(nameof(_Configuration.OutputQuality)); - if (_Configuration.OverrideForResizeImages is null) - throw new NullReferenceException(nameof(_Configuration.OverrideForResizeImages)); - if (_Configuration.PropertiesChangedForMetadata is null) - throw new NullReferenceException(nameof(_Configuration.PropertiesChangedForMetadata)); - if (_Configuration.PropertiesChangedForResize is null) - throw new NullReferenceException(nameof(_Configuration.PropertiesChangedForResize)); - if (_Configuration.NumberOfJitters is null) - throw new NullReferenceException(nameof(_Configuration.NumberOfJitters)); - if (_Configuration.NumberOfTimesToUpsample is null) - throw new NullReferenceException(nameof(_Configuration.NumberOfTimesToUpsample)); + string sourceFileName = "Halloween 2006 (112).jpg"; + string sourceDirectoryName = "Halloween 2006"; + Item item; bool reverse = false; - Property.Models.Item item; string original = "Original"; string aResultsFullGroupDirectory; string bResultsFullGroupDirectory; string cResultsFullGroupDirectory; List parseExceptions = new(); bool isValidImageFormatExtension = true; - Property.Models.A_Property? property = null; + Shared.Models.Property? property = null; Dictionary imageResizeKeyValuePairs; List> subFileTuples = new(); List> metadataCollection; int length = _PropertyConfiguration.RootDirectory.Length; string outputResolution = _Configuration.OutputResolutions[0]; (Model model, PredictorModel predictorModel, ModelParameter modelParameter) = GetModel(_Configuration); - Property.Models.PropertyLogic propertyLogic = GetPropertyLogic(reverse, model, predictorModel); + Property.Models.A_Property propertyLogic = GetPropertyLogic(reverse, model, predictorModel); string sourceDirectory = Path.Combine(_PropertyConfiguration.RootDirectory, sourceDirectoryName); _Logger.Information(_Configuration.ModelDirectory); aResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( @@ -209,9 +164,11 @@ public class UnitTestFace cResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory( _PropertyConfiguration, model, predictorModel, nameof(C_Resize), outputResolution, includeResizeGroup: true, includeModel: false, includePredictorModel: false); string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_PropertyConfiguration, nameof(Property.Models.A_Property), "{}"); - B_Metadata metadata = new(_Configuration.ForceMetadataLastWriteTimeToCreationTime.Value, _Configuration.PropertiesChangedForMetadata.Value); - (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters) = C_Resize.GetTuple(_Configuration.OutputExtension, _Configuration.OutputQuality.Value); - C_Resize resize = new(_Configuration.ForceResizeLastWriteTimeToCreationTime.Value, _Configuration.OverrideForResizeImages.Value, _Configuration.PropertiesChangedForResize.Value, _Configuration.ValidResolutions, imageCodecInfo, encoderParameters); + B_Metadata metadata = new(_Configuration.ForceMetadataLastWriteTimeToCreationTime, _Configuration.PropertiesChangedForMetadata); + _ = metadata.ToString(); + (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) = C_Resize.GetTuple(_Configuration.OutputExtension, _Configuration.OutputQuality); + C_Resize resize = new(_Configuration.ForceResizeLastWriteTimeToCreationTime, _Configuration.OverrideForResizeImages, _Configuration.PropertiesChangedForResize, _Configuration.ValidResolutions, imageCodecInfo, encoderParameters, filenameExtension); + _ = resize.ToString(); propertyLogic.AngleBracketCollection.AddRange(Property.Models.Stateless.IResult.GetDirectoryInfoCollection( _PropertyConfiguration, sourceDirectory, @@ -237,8 +194,8 @@ public class UnitTestFace collectionDescription: string.Empty, converted: true)); string sourceDirectoryFile = ".json"; - Property.Models.FileHolder fileHolder = new(Path.Combine(sourceDirectory, sourceFileName)); - string relativePath = Property.Models.Stateless.IPath.GetRelativePath(fileHolder.FullName, length); + FileHolder fileHolder = new(Path.Combine(sourceDirectory, sourceFileName)); + string relativePath = IPath.GetRelativePath(fileHolder.FullName, length); sourceDirectory = Path.Combine(aPropertySingletonDirectory, sourceDirectoryName); item = new(sourceDirectoryFile, relativePath, fileHolder, isValidImageFormatExtension, property, false, false); Assert.IsNotNull(item.ImageFileHolder); @@ -249,22 +206,18 @@ public class UnitTestFace } (int _, metadataCollection) = metadata.GetMetadataCollection(bResultsFullGroupDirectory, subFileTuples, parseExceptions, item); imageResizeKeyValuePairs = resize.GetResizeKeyValuePairs(cResultsFullGroupDirectory, subFileTuples, parseExceptions, original, metadataCollection, item); - Property.Models.FileHolder resizedFileHolder = new(Path.Combine(resize.AngleBracketCollection[0].Replace("<>", "()"), Path.GetFileName(item.ImageFileHolder.FullName))); - item.SetResizedFileHolder(resizedFileHolder); + FileHolder resizedFileHolder = new(Path.Combine(resize.AngleBracketCollection[0].Replace("<>", "()"), Path.GetFileName(item.ImageFileHolder.FullName))); + item.SetResizedFileHolder(resize.FilenameExtension, resizedFileHolder); resize.SaveResizedSubfile(outputResolution, cResultsFullGroupDirectory, subFileTuples, item, original, imageResizeKeyValuePairs); - item.SetResizedFileHolder(Property.Models.FileHolder.Refresh(resizedFileHolder)); + item.SetResizedFileHolder(resize.FilenameExtension, IFileHolder.Refresh(resizedFileHolder)); Assert.IsNotNull(item.ResizedFileHolder); - Image? image = FaceRecognition.LoadImageFile(item.ResizedFileHolder.FullName); + Image image = FaceRecognition.LoadImageFile(item.ResizedFileHolder.FullName); Assert.IsNotNull(image); - FaceRecognition faceRecognition = FaceRecognition.Create(modelParameter); - List locations = faceRecognition.FaceLocations(model, image, _Configuration.NumberOfTimesToUpsample.Value, sortByNormalizedPixelPercentage: true); - Assert.IsTrue(locations.Count == 2); - List<(FacePart, FacePoint[])[]> faceLandmarks = faceRecognition.GetFaceLandmarkCollection(image, _Configuration.NumberOfTimesToUpsample.Value, locations, predictorModel, model); - Assert.IsTrue(faceLandmarks.Count == 2); - faceLandmarks = faceRecognition.GetFaceLandmarkCollection(image, _Configuration.NumberOfTimesToUpsample.Value, faceLocations: null, predictorModel, model); - Assert.IsTrue(faceLandmarks.Count == 2); - List faceEncodings = faceRecognition.FaceEncodings(image, _Configuration.NumberOfTimesToUpsample.Value, knownFaceLocation: null, _Configuration.NumberOfJitters.Value, predictorModel, model); - Assert.IsTrue(faceEncodings.Count == 2); + FaceRecognition faceRecognition = new(_Configuration.NumberOfTimesToUpsample, _Configuration.NumberOfJitters, predictorModel, model, modelParameter); + List<(Location Location, FaceRecognitionDotNet.FaceEncoding? FaceEncoding, Dictionary? FaceParts)> collection; + collection = faceRecognition.GetCollection(image, includeFaceEncoding: true, includeFaceParts: true, sortByNormalizedPixelPercentage: true); + Assert.IsTrue(collection.Count == 2); + FaceRecognitionDotNet.FaceEncoding[] faceEncodings = (from l in collection where l.FaceEncoding is not null select l.FaceEncoding).ToArray(); List faceDistances = FaceRecognition.FaceDistances(faceEncodings, faceEncodings[0]); Assert.IsTrue(faceDistances.Count == 2); Assert.IsNotNull(sourceFileName); diff --git a/TestsWithFaceRecognitionDotNet/appsettings.Development.json b/TestsWithFaceRecognitionDotNet/appsettings.Development.json deleted file mode 100644 index 81aad60..0000000 --- a/TestsWithFaceRecognitionDotNet/appsettings.Development.json +++ /dev/null @@ -1,526 +0,0 @@ -{ - "Company": "Mike Phares", - "Linux": {}, - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Log4netProvider": "Debug", - "Microsoft.Hosting.Lifetime": "Information" - } - }, - "MaxDegreeOfParallelism": 6, - "Serilog": { - "Using": [ - "Serilog.Sinks.Console", - "Serilog.Sinks.File" - ], - "MinimumLevel": "Debug", - "WriteTo": [ - { - "Name": "Debug", - "Args": { - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" - } - }, - { - "Name": "Console", - "Args": { - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" - } - }, - { - "Name": "File", - "Args": { - "path": "%workingDirectory% - Log/log-.txt", - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}", - "rollingInterval": "Hour" - } - } - ], - "Enrich": [ - "FromLogContext", - "WithMachineName", - "WithThreadId" - ], - "Properties": { - "Application": "Sample" - } - }, - "WorkingDirectoryName": "PharesApps", - "Windows": { - "Configuration": { - "CheckJsonForDistanceResults": false, - "CrossDirectoryMaxItemsInDistanceCollection": 7, - "DateGroup": "2022-08-14", - "DistanceFactor": 8, - "FileNameDirectorySeparator": ".Z.", - "ForceMetadataLastWriteTimeToCreationTime": true, - "ForcePropertyLastWriteTimeToCreationTime": false, - "ForceResizeLastWriteTimeToCreationTime": true, - "LoadOrCreateThenSaveIndex": false, - "LocationConfidenceFactor": 2, - "MappedMaxIndex": 1034720, - "MaxImagesInDirectoryForTopLevelFirstPass": 50, - "MaxItemsInDistanceCollection": 50, - "ModelDirectory": "C:/GitHub/dlib-models", - "ModelName": "Hog", - "NumberOfJitters": 1, - "NumberOfTimesToUpsample": 1, - "OutputExtension": ".jpg", - "OutputQuality": 95, - "OverrideForFaceImages": false, - "OverrideForFaceLandmarkImages": false, - "OverrideForResizeImages": false, - "PaddingLoops": 5, - "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", - "PredictorModelName": "Large", - "PopulatePropertyId": true, - "PropertiesChangedForDistance": false, - "PropertiesChangedForFaces": false, - "PropertiesChangedForIndex": false, - "PropertiesChangedForMetadata": false, - "PropertiesChangedForProperty": false, - "PropertiesChangedForResize": false, - "Reverse": false, - "xRootDirectory": "C:/Tmp/phares/Pictures", - "RootDirectory": "F:/Tmp/Phares/Compare/Images 2022-08-14 - b756859b616424dc98b7742a64c15a8951632473 - III", - "SaveFullYearOfRandomFiles": true, - "SaveResizedSubFiles": true, - "SkipSearch": false, - "TestDistanceResults": true, - "WriteBitmapDataBytes": false, - "IgnoreExtensions": [ - ".gif", - ".GIF" - ], - "JuliePhares": [ - "1500-01-16_00", - "1500-01-19_00", - "1500-01-20_00", - "1500-01-21_00", - "1500-01-25_00", - "1500-01-26_00", - "1500-01-27_00", - "1500-02-13_00", - "1500-02-17_00", - "1500-02-24_00", - "1500-02-25_00", - "1500-04-03_00", - "1500-04-06_00", - "1500-04-19_00", - "1500-05-03_00", - "1500-05-18_00", - "1500-05-28_00", - "1500-06-16_00", - "1500-06-26_00", - "1500-06-27_00", - "1500-07-07_00", - "1500-07-16_00", - "1720-09-30_05", - "1500-07-26_00", - "1500-08-03_00", - "1500-08-23_00", - "1500-08-24_00", - "1500-09-16_00", - "1500-09-21_00", - "1500-09-28_00", - "1500-10-14_00", - "1500-11-07_00", - "1500-11-09_00", - "1720-09-28_20", - "1501-01-08_00", - "1501-01-12_00", - "1501-01-13_00", - "1501-01-30_00", - "1501-03-09_00", - "1501-03-14_00", - "1501-03-22_00", - "1501-04-07_00", - "1501-04-10_00", - "1501-04-19_00", - "1501-05-06_00", - "1956-09-19_00", - "2012-09-17_00", - "1998-05-21_00", - "1960-03-01_00", - "1976-03-08_00", - "2007-09-07_00", - "2000-04-07_00", - "1980-01-17_00", - "1958-01-30_00", - "1976-01-05_00", - "1982-05-02_00" - ], - "LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions": [ - "1920 x 1080" - ], - "LoadOrCreateThenSaveDistanceResultsForOutputResolutions": [ - "1920 x 1080" - ], - "LoadOrCreateThenSaveImageFacesResultsForOutputResolutions": [ - "1920 x 1080" - ], - "OutputResolutions": [ - "176 x 176", - "256 x 256", - "353 x 353", - "1024 x 768", - "1920 x 1080" - ], - "PropertyContentCollectionFiles": [], - "SaveFaceLandmarkForOutputResolutions": [ - "176 x 176", - "256 x 256" - ], - "SaveShortcutsForOutputResolutions": [ - "1920 x 1080" - ], - "ValidImageFormatExtensions": [ - ".bmp", - ".BMP", - ".gif", - ".GIF", - ".jpeg", - ".JPEG", - ".jpg", - ".JPG", - ".png", - ".PNG", - ".tiff", - ".TIFF" - ], - "ValidMetadataExtensions": [ - ".3gp", - ".3GP", - ".amr", - ".AMR", - ".avi", - ".AVI", - ".bmp", - ".BMP", - ".gif", - ".GIF", - ".ico", - ".ICO", - ".jpeg", - ".JPEG", - ".jpg", - ".JPG", - ".m4v", - ".M4V", - ".mov", - ".MOV", - ".mp4", - ".MP4", - ".mta", - ".MTA", - ".png", - ".PNG", - ".tiff", - ".TIFF" - ], - "ValidResolutions": [ - "176 x 176", - "256 x 256", - "353 x 353", - "1024 x 768", - "1280 x 720", - "1280 x 800", - "1376 x 768", - "1600 x 1200", - "1920 x 1080", - "2256 x 1496", - "3840 x 2160", - "7680 x 4320" - ], - "VerifyToSeason": [ - ". 2000", - ". 2001", - ". 2002", - ". 2003", - ". 2004", - ". 2005", - ". 2006", - ". 2007", - ". 2008", - ". 2009", - ". 2010", - ". 2011", - ". 2012", - ". 2013", - ". 2014", - ". 2015", - ". 2016", - ". 2017", - ". 2018", - ". 2019", - ". 2020", - ". 2021", - ". 2022", - ". 2023", - ". 2024", - ". 2025", - ". 2026", - ". 2027", - ". 2028", - ". 2029", - "=2000.0 Winter", - "=2002.1 Spring", - "=2002.4 Winter", - "=2003.0 Winter", - "=2003.1 Spring", - "=2003.3 Fall", - "=2003.4 Winter", - "=2004.0 Winter", - "=2005.1 Spring", - "=2005.2 Summer", - "=2005.3 Fall", - "=2005.4 Winter", - "=2006.0 Winter", - "=2006.1 Spring", - "=2006.3 Fall", - "=2007.0 Winter", - "=2007.2 Summer Logan Michael", - "=2007.2 Summer", - "=2007.3 Fall Logan Michael", - "=2007.4 Winter Logan Michael", - "=2008.0 Winter Logan Michael", - "=2008.1 Spring Logan Michael", - "=2008.2 Summer Logan Michael", - "=2008.2 Summer", - "=2008.3 Fall Logan Michael", - "=2009.0 Winter Logan Michael", - "=2009.0 Winter", - "=2009.1 Spring Logan Michael", - "=2009.1 Spring", - "=2009.2 Summer Logan Michael", - "=2009.2 Summer", - "=2009.3 Fall Logan Michael", - "=2009.3 Fall", - "=2009.4 Winter Logan Michael", - "=2009.4 Winter", - "=2010.0 Winter Logan Michael", - "=2010.0 Winter", - "=2010.1 Spring Logan Michael", - "=2010.1 Spring", - "=2010.2 Summer", - "=2010.3 Fall Logan Michael", - "=2010.3 Fall", - "=2010.4 Winter", - "=2011.0 Winter", - "=2011.1 Spring", - "=2011.2 Summer", - "=2011.3 Fall", - "=2011.4 Winter", - "=2012.0 Winter Chelsea 2012", - "=2012.0 Winter Chelsea", - "=2012.0 Winter", - "=2012.1 Spring Chelsea", - "=2012.1 Spring", - "=2012.2 Summer Chelsea", - "=2012.2 Summer", - "=2012.3 Fall Chelsea", - "=2012.3 Fall", - "=2012.4 Winter Chelsea", - "=2012.4 Winter", - "=2013.0 Winter Chelsea 2013", - "=2013.0 Winter Chelsea", - "=2013.0 Winter", - "=2013.1 Spring", - "=2013.2 Summer Chelsea", - "=2013.2 Summer", - "=2013.3 Fall Chelsea", - "=2013.3 Fall", - "=2013.4 Winter", - "=2014.0 Winter", - "=2014.1 Spring", - "=2014.2 Summer", - "=2014.3 Fall", - "=2014.4 Winter", - "=2015.0 Winter", - "=2015.1 Spring", - "=2015.2 Summer", - "=2015.3 Fall", - "=2015.4 Winter", - "=2016.0 Winter", - "=2016.1 Spring", - "=2016.2 Summer", - "=2016.3 Fall", - "=2016.4 Winter", - "=2017.1 Spring", - "=2017.2 Summer", - "=2017.3 Fall", - "=2017.4 Winter", - "=2018.0 Winter", - "=2018.1 Spring", - "=2018.3 Fall", - "=2018.4 Winter", - "=2019.0 Winter", - "=2019.1 Spring", - "=2019.2 Summer", - "=2019.3 Fall", - "=2019.4 Winter", - "=2020.0 Winter", - "=2020.1 Spring", - "=2020.2 Summer", - "=2020.3 Fall", - "=2020.4 Winter", - "=2021.1 Spring", - "=2021.2 Summer", - "=2021.3 Fall", - "=2021.4 Winter", - "=2022.0 Winter", - "=2022.1 Spring", - "Anthem 2015", - "April 2010", - "April 2013", - "December 2006", - "December 2010", - "Fall 2005", - "Fall 2015", - "Fall 2016", - "Fall 2017", - "Fall 2018", - "Fall 2019", - "Fall 2020", - "Fall 2021", - "February 2010", - "January 2015", - "July 2010", - "June 2010", - "Kids 2005", - "March 2013", - "May 2010", - "May 2011", - "May 2013", - "October 2005", - "October 2014", - "Spring 2013", - "Spring 2014", - "Spring 2016", - "Spring 2018", - "Spring 2019", - "Spring 2020", - "Summer 2011", - "Summer 2012", - "Summer 2013", - "Summer 2014", - "Summer 2015", - "Summer 2016", - "Summer 2017", - "Summer 2018", - "Summer 2020", - "Summer 2021", - "Winter 2015", - "Winter 2016", - "Winter 2017", - "Winter 2018", - "Winter 2019-2020", - "Winter 2020", - "zzz =2005.0 Winter Tracy Pictures", - "zzz =2005.1 Spring Tracy Pictures", - "zzz =2005.2 Summer Tracy Pictures", - "zzz =2005.3 Fall Tracy Pictures", - "zzz =2005.4 Winter Tracy Pictures", - "zzz =2006.1 Spring Tracy Pictures", - "zzz =2007.0 Winter Tracy Pictures", - "zzz =2007.2 Summer Tracy Pictures", - "zzz =2008.0 Winter Tracy Pictures", - "zzz =2008.2 Summer Tracy Pictures", - "zzz =2009.0 Winter Tracy Pictures", - "zzz =2009.2 Summer Tracy Pictures", - "zzz =2009.3 Fall Tracy Pictures", - "zzz =2009.4 Winter Tracy Pictures", - "zzz =2010.0 Winter Tracy Pictures", - "zzz =2010.1 Spring Tracy Pictures", - "zzz =2010.2 Summer Tracy Pictures", - "zzz =2010.3 Fall Tracy Pictures", - "zzz =2011.0 Winter Tracy Pictures", - "zzz =2011.1 Spring Tracy Pictures", - "zzz =2011.2 Summer Tracy Pictures", - "zzz =2011.3 Fall Tracy Pictures", - "zzz =2011.4 Winter Tracy Pictures", - "zzz =2012.0 Winter Tracy Pictures", - "zzz =2012.1 Spring Tracy Pictures", - "zzz =2012.2 Summer Tracy Pictures", - "zzz =2012.3 Fall Tracy Pictures", - "zzz =2012.4 Winter Tracy Pictures", - "zzz =2013.0 Winter Tracy Pictures", - "zzz =2013.1 Spring Tracy Pictures", - "zzz =2013.2 Summer Tracy Pictures", - "zzz =2013.3 Fall Tracy Pictures", - "zzz =2013.4 Winter Tracy Pictures", - "zzz =2014.0 Winter Tracy Pictures", - "zzz =2014.1 Spring Tracy Pictures", - "zzz =2014.2 Summer Tracy Pictures", - "zzz =2014.3 Fall Tracy Pictures", - "zzz =2014.4 Winter Tracy Pictures", - "zzz =2015.0 Winter Tracy Pictures" - ], - "MixedYearRelativePaths": [ - "Edited", - "Phares Slides", - "Rex Memorial", - "Scanned Grandma's Quilt", - "Scanned Pictures Of Kids", - "Scanned Prints", - "Slide in Name Order Originals (622)", - "Slides Pictures" - ], - "IgnoreRelativePaths": [ - "3757 W Whitman 2017", - "501 Playful Meadows 2006", - "501 Playful Meadows 2007", - "501 Playful Meadows 2008", - "501 Playful Meadows 2009", - "501 Playful Meadows 2010", - "501 Playful Meadows 2013", - "501 Playful Meadows 2015", - "6309 Evesham 2003", - "6309 Evesham 2004", - "Crystal's Wedding 2003", - "Danny's Wedding 2009", - "Door images 2019", - "Family Pictures 2006", - "Family Pictures 2007", - "Family Pictures 2011", - "Family Pictures 2013", - "GrandPrix 2004", - "Kids School Pictures 2004", - "Kristy 2002", - "Kristy Parents Wedding 2005", - "Logan Ultrasound 2007", - "Mandy's Dogs 2008", - "Motorcycles 2010", - "Motorcycles 2013", - "Motorcycles 2014", - "Phares Slides", - "Portrait Innovations April 2008", - "Portrait Innovations December 2007", - "Portrait Innovations June 2008", - "Portrait Innovations March 2012", - "The guys house 2000", - "Tracy Pictures 2005", - "Tracy Pictures 2006", - "Tracy Pictures 2007", - "Tracy Pictures 2008", - "Tracy Pictures 2009", - "Tracy Pictures 2010", - "Tracy Pictures 2011", - "Tracy Pictures 2012", - "Tracy Pictures 2013 Jan-July", - "Tracy Pictures 2013 July- Dec", - "Tracy Pictures 2014", - "Tracy Pictures 2015", - "Tracy Took The Kids 2006", - "Tracy's Bday 2012", - "Tracy's Wedding 2002", - "Trip to Colorado 10 2002", - "Trip to Colorado June 2002", - "Tub 2002", - "Vericruz 2011" - ] - } - } -} \ No newline at end of file diff --git a/TestsWithFaceRecognitionDotNet/appsettings.json b/TestsWithFaceRecognitionDotNet/appsettings.json deleted file mode 100644 index 2dcb0dc..0000000 --- a/TestsWithFaceRecognitionDotNet/appsettings.json +++ /dev/null @@ -1,525 +0,0 @@ -{ - "Company": "Mike Phares", - "Linux": {}, - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Log4netProvider": "Information", - "Microsoft.Hosting.Lifetime": "Information" - } - }, - "MaxDegreeOfParallelism": 12, - "Serilog": { - "Using": [ - "Serilog.Sinks.Console", - "Serilog.Sinks.File" - ], - "MinimumLevel": "Debug", - "WriteTo": [ - { - "Name": "Debug", - "Args": { - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" - } - }, - { - "Name": "Console", - "Args": { - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}" - } - }, - { - "Name": "File", - "Args": { - "path": "%workingDirectory% - Log/log-.txt", - "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] ({SourceContext}.{MethodName}) ({InstanceId}) ({RemoteIpAddress}) {Message}{NewLine}{Exception}", - "rollingInterval": "Hour" - } - } - ], - "Enrich": [ - "FromLogContext", - "WithMachineName", - "WithThreadId" - ], - "Properties": { - "Application": "Sample" - } - }, - "WorkingDirectoryName": "PharesApps", - "Windows": { - "Configuration": { - "CheckJsonForDistanceResults": false, - "CrossDirectoryMaxItemsInDistanceCollection": 7, - "DateGroup": "2022-08-14", - "DistanceFactor": 8, - "FileNameDirectorySeparator": ".Z.", - "ForceMetadataLastWriteTimeToCreationTime": false, - "ForcePropertyLastWriteTimeToCreationTime": false, - "ForceResizeLastWriteTimeToCreationTime": false, - "LoadOrCreateThenSaveIndex": false, - "LocationConfidenceFactor": 2, - "MappedMaxIndex": 1034720, - "MaxImagesInDirectoryForTopLevelFirstPass": 50, - "MaxItemsInDistanceCollection": 50, - "ModelDirectory": "C:/GitHub/dlib-models", - "ModelName": "Hog", - "NumberOfJitters": 1, - "NumberOfTimesToUpsample": 1, - "OutputExtension": ".jpg", - "OutputQuality": 95, - "OverrideForFaceImages": false, - "OverrideForFaceLandmarkImages": false, - "OverrideForResizeImages": false, - "PaddingLoops": 5, - "Pattern": "[^ABCDEFGHIJKLMNOPQRSTUVWXYZbcdfghjklmnpqrstvwxyz0-9]", - "PopulatePropertyId": true, - "PredictorModelName": "Large", - "PropertiesChangedForDistance": false, - "PropertiesChangedForFaces": false, - "PropertiesChangedForIndex": false, - "PropertiesChangedForMetadata": false, - "PropertiesChangedForProperty": false, - "PropertiesChangedForResize": false, - "Reverse": false, - "RootDirectory": "D:/Images", - "SaveFullYearOfRandomFiles": true, - "SaveResizedSubFiles": true, - "SkipSearch": false, - "TestDistanceResults": true, - "WriteBitmapDataBytes": false, - "IgnoreExtensions": [ - ".gif", - ".GIF" - ], - "JuliePhares": [ - "1500-01-16_00", - "1500-01-19_00", - "1500-01-20_00", - "1500-01-21_00", - "1500-01-25_00", - "1500-01-26_00", - "1500-01-27_00", - "1500-02-13_00", - "1500-02-17_00", - "1500-02-24_00", - "1500-02-25_00", - "1500-04-03_00", - "1500-04-06_00", - "1500-04-19_00", - "1500-05-03_00", - "1500-05-18_00", - "1500-05-28_00", - "1500-06-16_00", - "1500-06-26_00", - "1500-06-27_00", - "1500-07-07_00", - "1500-07-16_00", - "1720-09-30_05", - "1500-07-26_00", - "1500-08-03_00", - "1500-08-23_00", - "1500-08-24_00", - "1500-09-16_00", - "1500-09-21_00", - "1500-09-28_00", - "1500-10-14_00", - "1500-11-07_00", - "1500-11-09_00", - "1720-09-28_20", - "1501-01-08_00", - "1501-01-12_00", - "1501-01-13_00", - "1501-01-30_00", - "1501-03-09_00", - "1501-03-14_00", - "1501-03-22_00", - "1501-04-07_00", - "1501-04-10_00", - "1501-04-19_00", - "1501-05-06_00", - "1956-09-19_00", - "2012-09-17_00", - "1998-05-21_00", - "1960-03-01_00", - "1976-03-08_00", - "2007-09-07_00", - "2000-04-07_00", - "1980-01-17_00", - "1958-01-30_00", - "1976-01-05_00", - "1982-05-02_00" - ], - "LoadOrCreateThenSaveDirectoryDistanceResultsForOutputResolutions": [ - "1920 x 1080" - ], - "LoadOrCreateThenSaveDistanceResultsForOutputResolutions": [ - "1920 x 1080" - ], - "LoadOrCreateThenSaveImageFacesResultsForOutputResolutions": [ - "1920 x 1080" - ], - "OutputResolutions": [ - "176 x 176", - "256 x 256", - "353 x 353", - "1024 x 768", - "1920 x 1080" - ], - "PropertyContentCollectionFiles": [], - "SaveFaceLandmarkForOutputResolutions": [ - "176 x 176", - "256 x 256" - ], - "SaveShortcutsForOutputResolutions": [ - "1920 x 1080" - ], - "ValidImageFormatExtensions": [ - ".bmp", - ".BMP", - ".gif", - ".GIF", - ".jpeg", - ".JPEG", - ".jpg", - ".JPG", - ".png", - ".PNG", - ".tiff", - ".TIFF" - ], - "ValidMetadataExtensions": [ - ".3gp", - ".3GP", - ".amr", - ".AMR", - ".avi", - ".AVI", - ".bmp", - ".BMP", - ".gif", - ".GIF", - ".ico", - ".ICO", - ".jpeg", - ".JPEG", - ".jpg", - ".JPG", - ".m4v", - ".M4V", - ".mov", - ".MOV", - ".mp4", - ".MP4", - ".mta", - ".MTA", - ".png", - ".PNG", - ".tiff", - ".TIFF" - ], - "ValidResolutions": [ - "176 x 176", - "256 x 256", - "353 x 353", - "1024 x 768", - "1280 x 720", - "1280 x 800", - "1376 x 768", - "1600 x 1200", - "1920 x 1080", - "2256 x 1496", - "3840 x 2160", - "7680 x 4320" - ], - "VerifyToSeason": [ - ". 2000", - ". 2001", - ". 2002", - ". 2003", - ". 2004", - ". 2005", - ". 2006", - ". 2007", - ". 2008", - ". 2009", - ". 2010", - ". 2011", - ". 2012", - ". 2013", - ". 2014", - ". 2015", - ". 2016", - ". 2017", - ". 2018", - ". 2019", - ". 2020", - ". 2021", - ". 2022", - ". 2023", - ". 2024", - ". 2025", - ". 2026", - ". 2027", - ". 2028", - ". 2029", - "=2000.0 Winter", - "=2002.1 Spring", - "=2002.4 Winter", - "=2003.0 Winter", - "=2003.1 Spring", - "=2003.3 Fall", - "=2003.4 Winter", - "=2004.0 Winter", - "=2005.1 Spring", - "=2005.2 Summer", - "=2005.3 Fall", - "=2005.4 Winter", - "=2006.0 Winter", - "=2006.1 Spring", - "=2006.3 Fall", - "=2007.0 Winter", - "=2007.2 Summer Logan Michael", - "=2007.2 Summer", - "=2007.3 Fall Logan Michael", - "=2007.4 Winter Logan Michael", - "=2008.0 Winter Logan Michael", - "=2008.1 Spring Logan Michael", - "=2008.2 Summer Logan Michael", - "=2008.2 Summer", - "=2008.3 Fall Logan Michael", - "=2009.0 Winter Logan Michael", - "=2009.0 Winter", - "=2009.1 Spring Logan Michael", - "=2009.1 Spring", - "=2009.2 Summer Logan Michael", - "=2009.2 Summer", - "=2009.3 Fall Logan Michael", - "=2009.3 Fall", - "=2009.4 Winter Logan Michael", - "=2009.4 Winter", - "=2010.0 Winter Logan Michael", - "=2010.0 Winter", - "=2010.1 Spring Logan Michael", - "=2010.1 Spring", - "=2010.2 Summer", - "=2010.3 Fall Logan Michael", - "=2010.3 Fall", - "=2010.4 Winter", - "=2011.0 Winter", - "=2011.1 Spring", - "=2011.2 Summer", - "=2011.3 Fall", - "=2011.4 Winter", - "=2012.0 Winter Chelsea 2012", - "=2012.0 Winter Chelsea", - "=2012.0 Winter", - "=2012.1 Spring Chelsea", - "=2012.1 Spring", - "=2012.2 Summer Chelsea", - "=2012.2 Summer", - "=2012.3 Fall Chelsea", - "=2012.3 Fall", - "=2012.4 Winter Chelsea", - "=2012.4 Winter", - "=2013.0 Winter Chelsea 2013", - "=2013.0 Winter Chelsea", - "=2013.0 Winter", - "=2013.1 Spring", - "=2013.2 Summer Chelsea", - "=2013.2 Summer", - "=2013.3 Fall Chelsea", - "=2013.3 Fall", - "=2013.4 Winter", - "=2014.0 Winter", - "=2014.1 Spring", - "=2014.2 Summer", - "=2014.3 Fall", - "=2014.4 Winter", - "=2015.0 Winter", - "=2015.1 Spring", - "=2015.2 Summer", - "=2015.3 Fall", - "=2015.4 Winter", - "=2016.0 Winter", - "=2016.1 Spring", - "=2016.2 Summer", - "=2016.3 Fall", - "=2016.4 Winter", - "=2017.1 Spring", - "=2017.2 Summer", - "=2017.3 Fall", - "=2017.4 Winter", - "=2018.0 Winter", - "=2018.1 Spring", - "=2018.3 Fall", - "=2018.4 Winter", - "=2019.0 Winter", - "=2019.1 Spring", - "=2019.2 Summer", - "=2019.3 Fall", - "=2019.4 Winter", - "=2020.0 Winter", - "=2020.1 Spring", - "=2020.2 Summer", - "=2020.3 Fall", - "=2020.4 Winter", - "=2021.1 Spring", - "=2021.2 Summer", - "=2021.3 Fall", - "=2021.4 Winter", - "=2022.0 Winter", - "=2022.1 Spring", - "Anthem 2015", - "April 2010", - "April 2013", - "December 2006", - "December 2010", - "Fall 2005", - "Fall 2015", - "Fall 2016", - "Fall 2017", - "Fall 2018", - "Fall 2019", - "Fall 2020", - "Fall 2021", - "February 2010", - "January 2015", - "July 2010", - "June 2010", - "Kids 2005", - "March 2013", - "May 2010", - "May 2011", - "May 2013", - "October 2005", - "October 2014", - "Spring 2013", - "Spring 2014", - "Spring 2016", - "Spring 2018", - "Spring 2019", - "Spring 2020", - "Summer 2011", - "Summer 2012", - "Summer 2013", - "Summer 2014", - "Summer 2015", - "Summer 2016", - "Summer 2017", - "Summer 2018", - "Summer 2020", - "Summer 2021", - "Winter 2015", - "Winter 2016", - "Winter 2017", - "Winter 2018", - "Winter 2019-2020", - "Winter 2020", - "zzz =2005.0 Winter Tracy Pictures", - "zzz =2005.1 Spring Tracy Pictures", - "zzz =2005.2 Summer Tracy Pictures", - "zzz =2005.3 Fall Tracy Pictures", - "zzz =2005.4 Winter Tracy Pictures", - "zzz =2006.1 Spring Tracy Pictures", - "zzz =2007.0 Winter Tracy Pictures", - "zzz =2007.2 Summer Tracy Pictures", - "zzz =2008.0 Winter Tracy Pictures", - "zzz =2008.2 Summer Tracy Pictures", - "zzz =2009.0 Winter Tracy Pictures", - "zzz =2009.2 Summer Tracy Pictures", - "zzz =2009.3 Fall Tracy Pictures", - "zzz =2009.4 Winter Tracy Pictures", - "zzz =2010.0 Winter Tracy Pictures", - "zzz =2010.1 Spring Tracy Pictures", - "zzz =2010.2 Summer Tracy Pictures", - "zzz =2010.3 Fall Tracy Pictures", - "zzz =2011.0 Winter Tracy Pictures", - "zzz =2011.1 Spring Tracy Pictures", - "zzz =2011.2 Summer Tracy Pictures", - "zzz =2011.3 Fall Tracy Pictures", - "zzz =2011.4 Winter Tracy Pictures", - "zzz =2012.0 Winter Tracy Pictures", - "zzz =2012.1 Spring Tracy Pictures", - "zzz =2012.2 Summer Tracy Pictures", - "zzz =2012.3 Fall Tracy Pictures", - "zzz =2012.4 Winter Tracy Pictures", - "zzz =2013.0 Winter Tracy Pictures", - "zzz =2013.1 Spring Tracy Pictures", - "zzz =2013.2 Summer Tracy Pictures", - "zzz =2013.3 Fall Tracy Pictures", - "zzz =2013.4 Winter Tracy Pictures", - "zzz =2014.0 Winter Tracy Pictures", - "zzz =2014.1 Spring Tracy Pictures", - "zzz =2014.2 Summer Tracy Pictures", - "zzz =2014.3 Fall Tracy Pictures", - "zzz =2014.4 Winter Tracy Pictures", - "zzz =2015.0 Winter Tracy Pictures" - ], - "MixedYearRelativePaths": [ - "Edited", - "Phares Slides", - "Rex Memorial", - "Scanned Grandma's Quilt", - "Scanned Pictures Of Kids", - "Scanned Prints", - "Slide in Name Order Originals (622)", - "Slides Pictures" - ], - "IgnoreRelativePaths": [ - "3757 W Whitman 2017", - "501 Playful Meadows 2006", - "501 Playful Meadows 2007", - "501 Playful Meadows 2008", - "501 Playful Meadows 2009", - "501 Playful Meadows 2010", - "501 Playful Meadows 2013", - "501 Playful Meadows 2015", - "6309 Evesham 2003", - "6309 Evesham 2004", - "Crystal's Wedding 2003", - "Danny's Wedding 2009", - "Door images 2019", - "Family Pictures 2006", - "Family Pictures 2007", - "Family Pictures 2011", - "Family Pictures 2013", - "GrandPrix 2004", - "Kids School Pictures 2004", - "Kristy 2002", - "Kristy Parents Wedding 2005", - "Logan Ultrasound 2007", - "Mandy's Dogs 2008", - "Motorcycles 2010", - "Motorcycles 2013", - "Motorcycles 2014", - "Phares Slides", - "Portrait Innovations April 2008", - "Portrait Innovations December 2007", - "Portrait Innovations June 2008", - "Portrait Innovations March 2012", - "The guys house 2000", - "Tracy Pictures 2005", - "Tracy Pictures 2006", - "Tracy Pictures 2007", - "Tracy Pictures 2008", - "Tracy Pictures 2009", - "Tracy Pictures 2010", - "Tracy Pictures 2011", - "Tracy Pictures 2012", - "Tracy Pictures 2013 Jan-July", - "Tracy Pictures 2013 July- Dec", - "Tracy Pictures 2014", - "Tracy Pictures 2015", - "Tracy Took The Kids 2006", - "Tracy's Bday 2012", - "Tracy's Wedding 2002", - "Trip to Colorado 10 2002", - "Trip to Colorado June 2002", - "Tub 2002", - "Vericruz 2011" - ] - } - } -} \ No newline at end of file diff --git a/View-by-Distance-MKLink-Console.sln b/View-by-Distance-MKLink-Console.sln index 12ddf8d..693edbc 100644 --- a/View-by-Distance-MKLink-Console.sln +++ b/View-by-Distance-MKLink-Console.sln @@ -21,14 +21,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Property-Compare", "Propert EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Resize", "Resize\Resize.csproj", "{27D0D869-394D-4B07-83DF-2095B16026FC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Instance", "Instance\Instance.csproj", "{75D4A1EA-3727-4E28-9E87-FC1C77164ECD}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{B4FB6B43-36EC-404D-B934-5C695C6E32CC}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FaceRecognitionDotNet", "FaceRecognitionDotNet\FaceRecognitionDotNet.csproj", "{FAD03DA9-E8B1-4BBE-B8D0-2ADD2F2BC758}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestsWithFaceRecognitionDotNet", "TestsWithFaceRecognitionDotNet\TestsWithFaceRecognitionDotNet.csproj", "{A67D73C7-A1A1-4443-B681-776339CFA08A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Map", "Map\Map.csproj", "{960BBED6-BF2C-4337-8330-F858606F4343}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Instance", "Instance\Instance.csproj", "{8085C1EE-C4DB-43DE-8888-1C956D69CF91}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -74,10 +76,6 @@ Global {27D0D869-394D-4B07-83DF-2095B16026FC}.Debug|Any CPU.Build.0 = Debug|Any CPU {27D0D869-394D-4B07-83DF-2095B16026FC}.Release|Any CPU.ActiveCfg = Release|Any CPU {27D0D869-394D-4B07-83DF-2095B16026FC}.Release|Any CPU.Build.0 = Release|Any CPU - {75D4A1EA-3727-4E28-9E87-FC1C77164ECD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {75D4A1EA-3727-4E28-9E87-FC1C77164ECD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {75D4A1EA-3727-4E28-9E87-FC1C77164ECD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {75D4A1EA-3727-4E28-9E87-FC1C77164ECD}.Release|Any CPU.Build.0 = Release|Any CPU {B4FB6B43-36EC-404D-B934-5C695C6E32CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B4FB6B43-36EC-404D-B934-5C695C6E32CC}.Debug|Any CPU.Build.0 = Debug|Any CPU {B4FB6B43-36EC-404D-B934-5C695C6E32CC}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -90,5 +88,13 @@ Global {A67D73C7-A1A1-4443-B681-776339CFA08A}.Debug|Any CPU.Build.0 = Debug|Any CPU {A67D73C7-A1A1-4443-B681-776339CFA08A}.Release|Any CPU.ActiveCfg = Release|Any CPU {A67D73C7-A1A1-4443-B681-776339CFA08A}.Release|Any CPU.Build.0 = Release|Any CPU + {960BBED6-BF2C-4337-8330-F858606F4343}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {960BBED6-BF2C-4337-8330-F858606F4343}.Debug|Any CPU.Build.0 = Debug|Any CPU + {960BBED6-BF2C-4337-8330-F858606F4343}.Release|Any CPU.ActiveCfg = Release|Any CPU + {960BBED6-BF2C-4337-8330-F858606F4343}.Release|Any CPU.Build.0 = Release|Any CPU + {8085C1EE-C4DB-43DE-8888-1C956D69CF91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8085C1EE-C4DB-43DE-8888-1C956D69CF91}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8085C1EE-C4DB-43DE-8888-1C956D69CF91}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8085C1EE-C4DB-43DE-8888-1C956D69CF91}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/package.json b/package.json index dcfe240..9cd8736 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,17 @@ { "scripts": { - "AmazonUsername": "phares36@gmail.com", - "AmazonPassword":"JlPhgtv@63", "Alpha": "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "build": "dotnet build --runtime win-x64 --self-contained", + "cobertura": "ReportGenerator -reports:.vscode/TestResults/*/coverage.cobertura.xml -targetDir:.vscode/ReportGenerator/Cobertura/1d194f36-30a9-40e0-bf72-2ac275bd2fe2 -reportTypes:Cobertura", + "cobertura-rename": "node -e \"require('fs').rename('.vscode/ReportGenerator/Cobertura/1d194f36-30a9-40e0-bf72-2ac275bd2fe2/Cobertura.xml', '.vscode/ReportGenerator/Cobertura/1d194f36-30a9-40e0-bf72-2ac275bd2fe2/coverage.cobertura.xml', function(err) { if (err) console.log(err); console.log('File successfully renamed!') })\"", "dotnet-format": "dotnet format --report .vscode --verbosity detailed --severity warn", - "pull": "git pull", "garbage-collect": "git gc", + "html-Dark": "ReportGenerator -reports:.vscode/TestResults/*/coverage.cobertura.xml -targetDir:.vscode/ReportGenerator/Html_Dark/1d194f36 -reportTypes:Html_Dark", + "html-Dark-rename": "node -e \"require('fs').rename('.vscode/ReportGenerator/html_dark/1d194f36/index.htm', '.vscode/ReportGenerator/html_dark/1d194f36/_ index.htm', function(err) { if (err) console.log(err); console.log('File successfully renamed!') })\"", + "jsonSummary": "ReportGenerator -reports:.vscode/TestResults/*/coverage.cobertura.xml -targetDir:.vscode/ReportGenerator/JsonSummary/1d194f36 -reportTypes:JsonSummary", + "markdownSummary": "ReportGenerator -reports:.vscode/TestResults/*/coverage.cobertura.xml -targetDir:.vscode/ReportGenerator/MarkdownSummary/1d194f36 -reportTypes:MarkdownSummary", + "pull": "git pull", + "textSummary": "ReportGenerator -reports:.vscode/TestResults/*/coverage.cobertura.xml -targetDir:.vscode/ReportGenerator/TextSummary/1d194f36 -reportTypes:TextSummary", "A-Instance-Pictures": "set ASPNETCORE_ENVIRONMENT=Development&& dotnet run --project \"Instance\\Instance.csproj\" --runtime win-x64 --no-self-contained \"C:\\Tmp\\phares\\Pictures\" s", "B-Instance-Images--": "dotnet run --project \"Instance\\Instance.csproj\" --runtime win-x64 --no-self-contained \"D:\\Images\" s", "A-Shared-Build": "dotnet build \"Shared\\View-by-Distance.Shared.csproj\" --runtime win-x64 --no-self-contained", @@ -17,6 +22,8 @@ "Z-Instance-CUDA-Publish-": "dotnet publish \"Instance\\Instance.csproj\" --configuration Release --runtime win-x64 --verbosity normal --self-contained true -o \"D:\\net6.0\\View-by-Distance\\Instance-CUDA\\\"" }, "Notes": { + "AmazonUsername": "phares36@gmail.com", + "AmazonPassword": "JlPhgtv@63", "a": "Keep creating the .json file the same way", "b": "However load all .json files at the beginning", "c": "When looping through all files and file not in collection path&name or date is different from collection value",