diff --git a/Compare/Compare.cs b/Compare/Compare.cs index b406860..77500d2 100644 --- a/Compare/Compare.cs +++ b/Compare/Compare.cs @@ -54,8 +54,8 @@ public class Compare bool reverse = false; string outputExtension = ".jpg"; PredictorModel? predictorModel = null; - Dictionary personKeyValuePairs = new(); - Map.Models.MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, propertyConfiguration, outputExtension, personKeyValuePairs); + Shared.Models.Person[] people = Array.Empty(); + Map.Models.MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, propertyConfiguration, outputExtension, people); A_Property propertyLogic = GetPropertyLogic(reverse, model, outputExtension, predictorModel, mapLogic); foreach (string spelling in configuration.Spelling) { diff --git a/Instance/DlibDotNet.cs b/Instance/DlibDotNet.cs index 7d3ef08..d08aa5c 100644 --- a/Instance/DlibDotNet.cs +++ b/Instance/DlibDotNet.cs @@ -5,6 +5,7 @@ using System.Drawing.Imaging; using System.Text.Json; using View_by_Distance.FaceRecognitionDotNet; using View_by_Distance.Instance.Models; +using View_by_Distance.Map.Models; using View_by_Distance.Metadata.Models; using View_by_Distance.Property.Models; using View_by_Distance.Resize.Models; @@ -74,7 +75,8 @@ public class DlibDotNet else { _FirstRun = true; - _ = Directory.CreateDirectory(propertyRoot); + string peopleDateGroupDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(A2_People), "()"); + File.WriteAllText(Path.Combine(peopleDateGroupDirectory, "KnownPeople.txt"), string.Empty); } if (_FirstRun || !_ArgZeroIsConfigurationRootDirectory) people = Array.Empty(); @@ -92,14 +94,15 @@ public class DlibDotNet } { (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) = C_Resize.GetPngLowQuality(); - _Faces = new D_Face(configuration, argZero, model, modelParameter, predictorModel, imageCodecInfo, encoderParameters, filenameExtension); + (ImageCodecInfo hiddenImageCodecInfo, EncoderParameters hiddenEncoderParameters, string hiddenFilenameExtension) = C_Resize.GetGifLowQuality(); + _Faces = new D_Face(configuration, argZero, model, modelParameter, predictorModel, imageCodecInfo, encoderParameters, filenameExtension, hiddenImageCodecInfo, hiddenEncoderParameters, hiddenFilenameExtension); } { (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, model, predictorModel, argZero, propertyRoot, people, isSilent); + Search(propertyConfiguration, model, predictorModel, argZero, propertyRoot, people); if (!_FirstRun && _Exceptions.Count == 0 && _ArgZeroIsConfigurationRootDirectory) { long ticks = DateTime.Now.Ticks; @@ -273,6 +276,7 @@ public class DlibDotNet Shared.Models.Property property; List faceCollection; string original = "Original"; + FileHolder? resizedFileHolder; long ticks = DateTime.Now.Ticks; DateTime dateTime = DateTime.Now; List parseExceptions = new(); @@ -298,8 +302,6 @@ public class DlibDotNet (int metadataGroups, metadataCollection) = _Metadata.GetMetadataCollection(bResultsFullGroupDirectory, subFileTuples, parseExceptions, item); 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(_Resize.FilenameExtension, resizedFileHolder); imageResizeKeyValuePairs = _Resize.GetResizeKeyValuePairs(cResultsFullGroupDirectory, subFileTuples, parseExceptions, original, metadataCollection, item); if (_AppSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(C_Resize.GetResizeKeyValuePairs)); @@ -308,11 +310,10 @@ public class DlibDotNet _Resize.SaveResizedSubfile(outputResolution, cResultsFullGroupDirectory, subFileTuples, item, original, imageResizeKeyValuePairs); if (_AppSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(C_Resize.SaveResizedSubfile)); - item.SetResizedFileHolder(_Resize.FilenameExtension, Shared.Models.Stateless.Methods.IFileHolder.Refresh(resizedFileHolder)); } else if (outputResolution == _Configuration.OutputResolutions[0] && false) { - byte[] bytes = _Resize.GetResizedBytes(outputResolution, cResultsFullGroupDirectory, subFileTuples, item, property, imageResizeKeyValuePairs); + byte[] bytes = _Resize.GetResizedBytes(outputResolution, cResultsFullGroupDirectory, subFileTuples, item, imageResizeKeyValuePairs); if (_AppSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(C_Resize.GetResizedBytes)); string path = Path.Combine(resizedFileHolder.DirectoryName, resizedFileHolder.NameWithoutExtension); @@ -326,7 +327,7 @@ public class DlibDotNet int outputResolutionWidth = outputResolutionCollection[0]; int outputResolutionHeight = outputResolutionCollection[1]; int outputResolutionOrientation = outputResolutionCollection[2]; - faceCollection = _Faces.GetFaces(dResultsFullGroupDirectory, subFileTuples, parseExceptions, item, property, resizedFileHolder, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation); + faceCollection = _Faces.GetFaces(dResultsFullGroupDirectory, subFileTuples, parseExceptions, item, property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation); if (_AppSettings.MaxDegreeOfParallelism < 2) ticks = LogDelta(ticks, nameof(D_Face.GetFaces)); _Faces.SaveFaces(dResultsFullGroupDirectory, subFileTuples, parseExceptions, item, faceCollection); @@ -566,7 +567,7 @@ public class DlibDotNet converted: true)); } - private void FullDoWork(string argZero, Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string propertyRoot, long ticks, Map.Models.MapLogic mapLogic, A_Property propertyLogic, Container[] containers) + private void FullDoWork(string argZero, Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string propertyRoot, long ticks, MapLogic mapLogic, A_Property propertyLogic, Container[] containers) { if (_Log is null) throw new NullReferenceException(nameof(_Log)); @@ -686,7 +687,47 @@ public class DlibDotNet return results; } - private void Search(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string argZero, string propertyRoot, Person[] people, bool isSilent) + private void MapLogic(string argZero, Container[] containers, long ticks, string dResultsFullGroupDirectory, string zResultsFullGroupDirectory, string d2ResultsFullGroupDirectory, MapLogic mapLogic, string outputResolution) + { + mapLogic.UseKeyValuePairsSaveFaceEncoding(containers); + foreach (Container container in containers) + { + mapLogic.AddToMapping(container.Items); + if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) + mapLogic.SaveShortcuts(_Configuration.JuliePhares, dResultsFullGroupDirectory, ticks, container.Items); + } + mapLogic.SaveAllCollection(); + if (_Configuration.SaveResizedSubfiles) + { + string dFacesContentDirectory; + string zPropertyHolderContentDirectory; + string zPropertyHolderSingletonDirectory; + string zPropertyHolderCollectionDirectory; + dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, "()"); + zPropertyHolderSingletonDirectory = Path.Combine(zResultsFullGroupDirectory, "{}"); + zPropertyHolderContentDirectory = Path.Combine(zResultsFullGroupDirectory, $"({ticks})"); + zPropertyHolderCollectionDirectory = Path.Combine(zResultsFullGroupDirectory, $"[{ticks}]"); + mapLogic.SaveNotMappedPersonKeys(zPropertyHolderContentDirectory); + _ = LogDeltaInMinutes(ticks, nameof(mapLogic.SaveNotMappedPersonKeys)); + Dictionary> keyValuePairs = _Distance.ParallelWork(_AppSettings.MaxDegreeOfParallelism, _Configuration.IgnoreRelativePaths, argZero, ticks, containers); + _ = LogDeltaInSeconds(ticks, nameof(E_Distance.ParallelWork)); + Dictionary> strippedKeyValuePairs = Strip(keyValuePairs); + List<(string, int, Mapping, DateTime, bool?, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>)> collection = Convert(keyValuePairs); + mapLogic.SaveMapping(argZero, containers, dFacesContentDirectory, d2ResultsFullGroupDirectory, zPropertyHolderContentDirectory); + _ = LogDeltaInMinutes(ticks, nameof(mapLogic.SaveMapping)); + _Distance.AddToFaceDistance(_AppSettings.MaxDegreeOfParallelism, argZero, ticks, mapLogic, containers, outputResolution, collection); + _ = LogDeltaInSeconds(ticks, nameof(_Distance.AddToFaceDistance)); + mapLogic.AddToClosest(_AppSettings.MaxDegreeOfParallelism, argZero, containers); + _ = LogDeltaInMinutes(ticks, nameof(mapLogic.AddToClosest)); + mapLogic.SaveClosest(argZero, containers, dFacesContentDirectory, d2ResultsFullGroupDirectory, zPropertyHolderContentDirectory); + _ = LogDeltaInMinutes(ticks, nameof(mapLogic.SaveClosest)); + E_Distance.SavePropertyHolders(argZero, containers, zPropertyHolderSingletonDirectory); + _ = LogDeltaInSeconds(ticks, nameof(E_Distance.SavePropertyHolders)); + } + _ = LogDeltaInSeconds(ticks, nameof(MapLogic)); + } + + private void Search(Property.Models.Configuration configuration, Model? model, PredictorModel? predictorModel, string argZero, string propertyRoot, Person[] people) { if (_Log is null) throw new NullReferenceException(nameof(_Log)); @@ -699,8 +740,7 @@ public class DlibDotNet string eResultsFullGroupDirectory; string zResultsFullGroupDirectory; string d2ResultsFullGroupDirectory; - Dictionary personKeyValuePairs = A2_People.Convert(people); - Map.Models.MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FilenameExtension, personKeyValuePairs); + MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FilenameExtension, _Faces.FilenameExtension, _Faces.HiddenFilenameExtension, _FaceParts.FilenameExtension, people); A_Property propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FilenameExtension, _Configuration.Reverse, model, predictorModel, mapLogic.IndicesFromNew, mapLogic.KeyValuePairs); if (string.IsNullOrEmpty(configuration.RootDirectory)) containers = A_Property.Get(configuration, propertyLogic); @@ -714,39 +754,7 @@ public class DlibDotNet (aResultsFullGroupDirectory, bResultsFullGroupDirectory, cResultsFullGroupDirectory, dResultsFullGroupDirectory, d2ResultsFullGroupDirectory, eResultsFullGroupDirectory, zResultsFullGroupDirectory) = GetResultsFullGroupDirectories(configuration, model, predictorModel, outputResolution); if (_ArgZeroIsConfigurationRootDirectory && _Exceptions.Count == 0 && outputResolution == _Configuration.OutputResolutions[0]) { - mapLogic.UseKeyValuePairsSaveFaceEncoding(containers); - foreach (Container container in containers) - { - mapLogic.AddToMapping(container.Items); - if (_Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) - mapLogic.SaveShortcuts(_Configuration.JuliePhares, dResultsFullGroupDirectory, ticks, container.Items); - } - mapLogic.SaveAllCollection(); - if (_Configuration.SaveResizedSubfiles) - { - string dFacesContentDirectory; - string zPropertyHolderContentDirectory; - string zPropertyHolderSingletonDirectory; - string zPropertyHolderCollectionDirectory; - dFacesContentDirectory = Path.Combine(dResultsFullGroupDirectory, "()"); - zPropertyHolderSingletonDirectory = Path.Combine(zResultsFullGroupDirectory, "{}"); - zPropertyHolderContentDirectory = Path.Combine(zResultsFullGroupDirectory, $"({ticks})"); - zPropertyHolderCollectionDirectory = Path.Combine(zResultsFullGroupDirectory, $"[{ticks}]"); - Dictionary> keyValuePairs = _Distance.ParallelWork(_AppSettings.MaxDegreeOfParallelism, _Configuration.IgnoreRelativePaths, argZero, ticks, containers); - _ = LogDeltaInSeconds(ticks, nameof(E_Distance.ParallelWork)); - Dictionary> strippedKeyValuePairs = Strip(keyValuePairs); - List<(string, int, Mapping, DateTime, bool?, List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)>)> collection = Convert(keyValuePairs); - mapLogic.SaveMapping(argZero, containers, dFacesContentDirectory, d2ResultsFullGroupDirectory, zPropertyHolderContentDirectory); - _ = LogDeltaInMinutes(ticks, nameof(mapLogic.SaveMapping)); - _Distance.AddToFaceDistance(_AppSettings.MaxDegreeOfParallelism, argZero, ticks, mapLogic, containers, outputResolution, collection); - _ = LogDeltaInSeconds(ticks, nameof(_Distance.AddToFaceDistance)); - mapLogic.AddToClosest(_AppSettings.MaxDegreeOfParallelism, argZero, containers); - _ = LogDeltaInMinutes(ticks, nameof(mapLogic.AddToClosest)); - mapLogic.SaveClosest(argZero, containers, dFacesContentDirectory, d2ResultsFullGroupDirectory, zPropertyHolderContentDirectory); - _ = LogDeltaInMinutes(ticks, nameof(mapLogic.SaveClosest)); - E_Distance.SavePropertyHolders(argZero, containers, zPropertyHolderSingletonDirectory); - _ = LogDeltaInSeconds(ticks, nameof(E_Distance.SavePropertyHolders)); - } + MapLogic(argZero, containers, ticks, dResultsFullGroupDirectory, zResultsFullGroupDirectory, d2ResultsFullGroupDirectory, mapLogic, outputResolution); if (!_Configuration.LoadOrCreateThenSaveImageFacesResultsForOutputResolutions.Any()) break; if (_FileKeyValuePairs.Any()) diff --git a/Instance/Models/_A2_People.cs b/Instance/Models/_A2_People.cs index 1464614..9f8345f 100644 --- a/Instance/Models/_A2_People.cs +++ b/Instance/Models/_A2_People.cs @@ -73,18 +73,4 @@ internal class A2_People return results.ToArray(); } - internal static Dictionary Convert(Person[] people) - { - Dictionary results = new(); - string personKey; - foreach (Person person in people) - { - personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(person.Birthday); - if (results.ContainsKey(personKey)) - break; - results.Add(personKey, person); - } - return results; - } - } \ No newline at end of file diff --git a/Instance/Models/_D2_FaceParts.cs b/Instance/Models/_D2_FaceParts.cs index bdeeccc..cb935dd 100644 --- a/Instance/Models/_D2_FaceParts.cs +++ b/Instance/Models/_D2_FaceParts.cs @@ -15,8 +15,10 @@ namespace View_by_Distance.Instance.Models; internal class D2_FaceParts { + protected readonly string _FilenameExtension; + public string FilenameExtension => _FilenameExtension; + private readonly Serilog.ILogger? _Log; - private readonly string _FilenameExtension; private readonly Configuration _Configuration; private readonly ImageCodecInfo _ImageCodecInfo; private readonly EncoderParameters _EncoderParameters; diff --git a/Instance/Models/_D_Face.cs b/Instance/Models/_D_Face.cs index 091256f..31018c9 100644 --- a/Instance/Models/_D_Face.cs +++ b/Instance/Models/_D_Face.cs @@ -19,29 +19,39 @@ public class D_Face internal List AngleBracketCollection { get; } + protected readonly string _FilenameExtension; + public string FilenameExtension => _FilenameExtension; + + protected readonly string _HiddenFilenameExtension; + public string HiddenFilenameExtension => _HiddenFilenameExtension; + private readonly Model _Model; private readonly string _ArgZero; private readonly Serilog.ILogger? _Log; - private readonly string _FilenameExtension; private readonly Configuration _Configuration; + private readonly ImageCodecInfo _ImageCodecInfo; private readonly ModelParameter _ModelParameter; private readonly PredictorModel _PredictorModel; - private readonly ImageCodecInfo _ImageCodecInfo; private readonly EncoderParameters _EncoderParameters; + private readonly ImageCodecInfo _HiddenImageCodecInfo; + private readonly EncoderParameters _HiddenEncoderParameters; private readonly JsonSerializerOptions _WriteIndentedJsonSerializerOptions; - internal D_Face(Configuration configuration, string argZero, Model model, ModelParameter modelParameter, PredictorModel predictorModel, ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) + internal D_Face(Configuration configuration, string argZero, Model model, ModelParameter modelParameter, PredictorModel predictorModel, ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension, ImageCodecInfo hiddenImageCodecInfo, EncoderParameters hiddenEncoderParameters, string hiddenFilenameExtension) { _Model = model; _ArgZero = argZero; _Configuration = configuration; + _ImageCodecInfo = imageCodecInfo; _ModelParameter = modelParameter; _PredictorModel = predictorModel; - _ImageCodecInfo = imageCodecInfo; _EncoderParameters = encoderParameters; _FilenameExtension = filenameExtension; - AngleBracketCollection = new List(); _Log = Serilog.Log.ForContext(); + AngleBracketCollection = new List(); + _HiddenImageCodecInfo = hiddenImageCodecInfo; + _HiddenEncoderParameters = hiddenEncoderParameters; + _HiddenFilenameExtension = hiddenFilenameExtension; _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; } @@ -133,7 +143,7 @@ public class D_Face return result; } - private void SaveFaces(FileHolder resizedFileHolder, List<(Face, string)> collection) + private void SaveFaces(FileHolder resizedFileHolder, List<(Face, FileInfo?, string)> collection) { int width; int height; @@ -142,8 +152,10 @@ public class D_Face Bitmap preRotated; Rectangle rectangle; using Bitmap source = new(resizedFileHolder.FullName); - foreach ((Face face, string fileName) in collection) + foreach ((Face face, FileInfo? fileInfo, string fileName) in collection) { + if (fileInfo is null) + continue; 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); @@ -156,23 +168,40 @@ public class D_Face { using (graphics = Graphics.FromImage(preRotated)) graphics.DrawImage(source, new Rectangle(0, 0, width, height), rectangle, GraphicsUnit.Pixel); - preRotated.Save(fileName, _ImageCodecInfo, _EncoderParameters); + preRotated.Save(fileInfo.FullName, _ImageCodecInfo, _EncoderParameters); } + if (File.Exists(fileName)) + File.Delete(fileName); + location = Shared.Models.Stateless.Methods.ILocation.GetLocation(IFaceDistance.HiddenImageFactor, face.Location, source.Height, source.Width, collection.Count); + if (location is null) + continue; + width = location.Right - location.Left; + height = location.Bottom - location.Top; + rectangle = new Rectangle(location.Left, location.Top, width, height); + using (preRotated = new(width, height)) + { + using (graphics = Graphics.FromImage(preRotated)) + graphics.DrawImage(source, new Rectangle(0, 0, width, height), rectangle, GraphicsUnit.Pixel); + preRotated.Save(fileName, _HiddenImageCodecInfo, _HiddenEncoderParameters); + } + File.SetAttributes(fileName, FileAttributes.Hidden); } } - private List GetFaces(FileHolder resizedFileHolder, Item item, Shared.Models.Property property, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation) + private List GetFaces(Item item, Shared.Models.Property property, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation) { List results = new(); if (item.ImageFileHolder is null) throw new NullReferenceException(nameof(item.ImageFileHolder)); + if (item.ResizedFileHolder is null) + throw new NullReferenceException(nameof(item.ResizedFileHolder)); FaceRecognitionDotNet.Image? unknownImage; - if (!resizedFileHolder.Exists) + if (!item.ResizedFileHolder.Exists) unknownImage = null; else { try - { unknownImage = FaceRecognition.LoadImageFile(resizedFileHolder.FullName); } + { unknownImage = FaceRecognition.LoadImageFile(item.ResizedFileHolder.FullName); } catch (Exception) { unknownImage = null; } } @@ -214,7 +243,7 @@ public class D_Face #pragma warning restore CA1416 - internal List GetFaces(string dResultsFullGroupDirectory, List> subFileTuples, List parseExceptions, Item item, Shared.Models.Property property, FileHolder resizedFileHolder, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation) + internal List GetFaces(string dResultsFullGroupDirectory, List> subFileTuples, List parseExceptions, Item item, Shared.Models.Property property, int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation) { List? results; if (item.Property?.Id is null) @@ -277,8 +306,6 @@ public class D_Face 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}>"); @@ -293,7 +320,7 @@ public class D_Face } if (results is null) { - results = GetFaces(resizedFileHolder, item, property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation); + results = GetFaces(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(); @@ -330,7 +357,7 @@ public class D_Face bool check = false; string parentCheck; double deterministicHashCodeKey; - List<(Face, string)> collection = new(); + List<(Face, FileInfo?, 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(); @@ -341,7 +368,7 @@ public class D_Face { if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) { - collection.Add(new(face, string.Empty)); + collection.Add(new(face, null, string.Empty)); continue; } deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face); @@ -354,7 +381,7 @@ public class D_Face if (File.Exists(parentCheck)) File.Delete(parentCheck); } - collection.Add(new(face, fileInfo.FullName)); + collection.Add(new(face, fileInfo, Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_HiddenFilenameExtension}"))); if (_Configuration.OverrideForFaceImages) check = true; else if (!fileInfo.Exists) diff --git a/Instance/Models/_E_Distance.cs b/Instance/Models/_E_Distance.cs index 4b6ac29..c68c307 100644 --- a/Instance/Models/_E_Distance.cs +++ b/Instance/Models/_E_Distance.cs @@ -612,6 +612,15 @@ internal class E_Distance return results; } + private static void SetNonFiltered(List<(FaceRecognitionDotNet.FaceEncoding, MappingContainer)> collection) + { + foreach ((FaceRecognitionDotNet.FaceEncoding _, MappingContainer mappingContainer) in collection) + { + if (mappingContainer.Mapping.Filtered is null) + mappingContainer.Mapping.SetFiltered(value: false); + } + } + private Dictionary> GetThreeSigmaFaceEncodings(int maxDegreeOfParallelism, long ticks, Dictionary> keyValuePairs) { if (_Log is null) @@ -644,8 +653,9 @@ internal class E_Distance faceDistances = FaceRecognition.FaceDistances(faceEncodings, faceEncodings[selectedIndex]); for (int i = 0; i < faceEncodings.Count; i++) collection[i].MappingContainer.SetDistance(faceDistances[i]); - if (collection.Count > 1) + if (collection.Count > 3) SetFiltered(collection); + SetNonFiltered(collection); totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); _Log.Information($"{keyValuePairsCount:0000}) {totalSeconds} total second(s) - {keyValuePair.Key} - {collection[selectedIndex].MappingContainer.Mapping.DisplayDirectoryName}"); } @@ -656,6 +666,11 @@ internal class E_Distance { Dictionary> results; Dictionary> keyValuePairs = Map.Models.Stateless.IMapLogic.GetKeyValuePairs(ignoreRelativePaths, argZero, containers); + if (!keyValuePairs.Any()) + { + Map.Models.Stateless.IMapLogic.SetSingleImage(ignoreRelativePaths, argZero, containers); + keyValuePairs = Map.Models.Stateless.IMapLogic.GetKeyValuePairs(ignoreRelativePaths, argZero, containers); + } results = GetThreeSigmaFaceEncodings(maxDegreeOfParallelism, ticks, keyValuePairs); return results; } @@ -719,11 +734,11 @@ internal class E_Distance if (item.ImageFileHolder is null || item.Property is null || !item.Faces.Any() || !item.Closest.Any()) continue; json = JsonSerializer.Serialize(item, jsonSerializerOptions); - fileInfo = new(string.Concat(zPropertyHolderSingletonDirectory, item.RelativePath, ".json")); + fileInfo = new(Path.GetFullPath(string.Concat(zPropertyHolderSingletonDirectory, item.RelativePath, ".json"))); if (fileInfo.Directory is null) continue; if (!fileInfo.Directory.Exists) - fileInfo.Directory.Create(); + continue; _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true); } } diff --git a/Map/Models/MapLogic.cs b/Map/Models/MapLogic.cs index a7ca2ca..ffb5a56 100644 --- a/Map/Models/MapLogic.cs +++ b/Map/Models/MapLogic.cs @@ -2,7 +2,6 @@ using System.Diagnostics; using System.Text.Json; using View_by_Distance.Property.Models; using View_by_Distance.Shared.Models; -using View_by_Distance.Shared.Models.Properties; using WindowsShortcutFactory; namespace View_by_Distance.Map.Models; @@ -11,6 +10,7 @@ public class MapLogic { protected readonly List _SkipCollection; + protected readonly List _NotMappedPersonKeys; protected readonly List<(int, string[])> _AllCollection; protected readonly Dictionary _KeyValuePairs; protected readonly Dictionary _IndicesFromNew; @@ -25,23 +25,30 @@ public class MapLogic public Dictionary IndicesFromNew => _IndicesFromNew; private readonly Serilog.ILogger? _Log; - private readonly string _OutputExtension; private readonly Configuration _Configuration; + private readonly string _FacesFilenameExtension; + private readonly string _ResizeFilenameExtension; + private readonly string _FacePartsFilenameExtension; + private readonly string _FacesHiddenFilenameExtension; - public MapLogic(int maxDegreeOfParallelism, Configuration configuration, string outputExtension, Dictionary personKeyValuePairs) + public MapLogic(int maxDegreeOfParallelism, Configuration configuration, string resizeFilenameExtension, string facesFilenameExtension, string facesHiddenFilenameExtension, string facePartsFilenameExtension, Person[] people) { _AllCollection = new(); _Configuration = configuration; _Log = Serilog.Log.ForContext(); + _FacesFilenameExtension = facesFilenameExtension; + _ResizeFilenameExtension = resizeFilenameExtension; + _FacePartsFilenameExtension = facePartsFilenameExtension; + _FacesHiddenFilenameExtension = facesHiddenFilenameExtension; Dictionary? deterministicHashCodeUnknownFaceKeyValuePairs; if (configuration.VerifyToSeason is null || !configuration.VerifyToSeason.Any()) throw new Exception(); string json; string[] files; string fullPath; - _OutputExtension = outputExtension; List skipCollection = new(); Dictionary? keyValuePairs; + List notMappedPersonKeys = new(); List>? collection; string deterministicHashCodeContentDirectory; Dictionary indicesFromNew = new(); @@ -52,6 +59,7 @@ public class MapLogic Dictionary peopleKeyValuePairs = new(); if (string.IsNullOrEmpty(rootDirectoryParent)) throw new NullReferenceException(nameof(rootDirectoryParent)); + string deterministicHashCodeRootDirectory = Path.Combine(rootDirectoryParent, "DeterministicHashCode"); files = Directory.GetFiles(rootDirectoryParent, "DeterministicHashCode*.json", SearchOption.TopDirectoryOnly); if (files.Length != 1) deterministicHashCodeUnknownFaceKeyValuePairs = new(); @@ -62,11 +70,9 @@ public class MapLogic if (deterministicHashCodeUnknownFaceKeyValuePairs is null) throw new NullReferenceException(nameof(deterministicHashCodeUnknownFaceKeyValuePairs)); } - string[] directories = Directory.GetDirectories(rootDirectoryParent, "DeterministicHashCode", SearchOption.TopDirectoryOnly); - if (!directories.Any()) - deterministicHashCodeContentDirectory = string.Empty; - else - deterministicHashCodeContentDirectory = Stateless.ByDeterministicHashCode.SetByRef(_OutputExtension, personKeyValuePairs, skipCollection, peopleKeyValuePairs, deterministicHashCodeUnknownFaceKeyValuePairs, deterministicHashCodeKeyValuePairs, incorrectDeterministicHashCodeKeyValuePairs, directories[0]); + if (!Directory.Exists(deterministicHashCodeRootDirectory)) + _ = Directory.CreateDirectory(deterministicHashCodeRootDirectory); + deterministicHashCodeContentDirectory = Stateless.ByDeterministicHashCode.SetByRef(_ResizeFilenameExtension, people, skipCollection, peopleKeyValuePairs, notMappedPersonKeys, deterministicHashCodeUnknownFaceKeyValuePairs, deterministicHashCodeKeyValuePairs, incorrectDeterministicHashCodeKeyValuePairs, deterministicHashCodeRootDirectory); if (!deterministicHashCodeUnknownFaceKeyValuePairs.Any()) sixCharacterNamedFaceInfo = new(); else @@ -113,6 +119,7 @@ public class MapLogic _KeyValuePairs = keyValuePairs; _IndicesFromNew = indicesFromNew; _SkipCollection = skipCollection; + _NotMappedPersonKeys = notMappedPersonKeys; _PeopleKeyValuePairs = peopleKeyValuePairs; _SixCharacterNamedFaceInfo = sixCharacterNamedFaceInfo; _DeterministicHashCodeKeyValuePairs = deterministicHashCodeKeyValuePairs; @@ -121,6 +128,10 @@ public class MapLogic _DeterministicHashCodeUnknownFaceKeyValuePairs = deterministicHashCodeUnknownFaceKeyValuePairs; } + public MapLogic(int maxDegreeOfParallelism, Configuration configuration, string outputExtension, Person[] people) : + this(maxDegreeOfParallelism, configuration, outputExtension, outputExtension, outputExtension, outputExtension, people) + { } + public bool Skip(double deterministicHashCodeKey) => _SkipCollection.Contains(deterministicHashCodeKey); public void SaveShortcuts(string[] juliePhares, string dResultsFullGroupDirectory, long ticks, List items) @@ -297,21 +308,13 @@ public class MapLogic personKeys.AddRange(_DeterministicHashCodeKeyValuePairs[deterministicHashCodeKey]); for (int i = 0; i < personKeys.Count; i++) { - if (_PeopleKeyValuePairs.ContainsKey(personKeys[i])) - { - person = _PeopleKeyValuePairs[personKeys[i]]; - personBirthday = person.PersonBirthdays[0]; - approximateYears = person.ApproximateYears; - displayDirectoryName = person.DisplayDirectoryName; - personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthday); - } - else - { - approximateYears = null; - personKey = personKeys[i]; - displayDirectoryName = "_ _ _"; - personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKey); - } + if (!_PeopleKeyValuePairs.ContainsKey(personKeys[i])) + continue; + person = _PeopleKeyValuePairs[personKeys[i]]; + personBirthday = person.PersonBirthdays[0]; + approximateYears = person.ApproximateYears; + displayDirectoryName = person.DisplayDirectoryName; + personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthday); if (personBirthday is null) continue; mapping = new(approximateYears, displayDirectoryName, face.Location.NormalizedPixelPercentage, personBirthday, personKey); @@ -325,21 +328,13 @@ public class MapLogic personKeys.AddRange(_DeterministicHashCodeUnknownFaceKeyValuePairs[item.Property.Id.Value]); for (int i = 0; i < personKeys.Count; i++) { - if (_PeopleKeyValuePairs.ContainsKey(personKeys[i])) - { - person = _PeopleKeyValuePairs[personKeys[i]]; - personBirthday = person.PersonBirthdays[0]; - approximateYears = person.ApproximateYears; - displayDirectoryName = person.DisplayDirectoryName; - personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthday); - } - else - { - approximateYears = null; - personKey = personKeys[i]; - displayDirectoryName = "_ _ _"; - personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKey); - } + if (!_PeopleKeyValuePairs.ContainsKey(personKeys[i])) + continue; + person = _PeopleKeyValuePairs[personKeys[i]]; + personBirthday = person.PersonBirthdays[0]; + approximateYears = person.ApproximateYears; + displayDirectoryName = person.DisplayDirectoryName; + personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthday); if (personBirthday is null) continue; mapping = new(approximateYears, displayDirectoryName, personBirthday, personKey); @@ -349,6 +344,72 @@ public class MapLogic } } + private void SaveContainers(List saveContainers) + { + WindowsShortcut windowsShortcut; + string[] directories = (from l in saveContainers select l.Directory).Distinct().ToArray(); + foreach (string directory in directories) + { + if (string.IsNullOrEmpty(directory)) + continue; + if (!Directory.Exists(directory)) + _ = Directory.CreateDirectory(directory); + } + foreach (SaveContainer saveContainer in saveContainers) + { + if (string.IsNullOrEmpty(saveContainer.Directory) || string.IsNullOrEmpty(saveContainer.CheckFile) || saveContainer.ResizedFileHolder is null || saveContainer.FaceFileHolder is null || !string.IsNullOrEmpty(saveContainer.Json)) + continue; + if (File.Exists(saveContainer.CheckFile)) + continue; + if (saveContainer.FaceFileHolder.Exists) + File.Copy(saveContainer.FaceFileHolder.FullName, saveContainer.CheckFile); + else + File.Copy(saveContainer.ResizedFileHolder.FullName, saveContainer.CheckFile); + if (saveContainer.HiddenFaceFileHolder is not null && saveContainer.HiddenFaceFileHolder.Exists) + File.Copy(saveContainer.HiddenFaceFileHolder.FullName, Path.ChangeExtension(saveContainer.CheckFile, _FacesHiddenFilenameExtension)); + else if (saveContainer.FacePartsFileHolder is not null && saveContainer.FacePartsFileHolder.Exists) + File.Copy(saveContainer.FacePartsFileHolder.FullName, Path.ChangeExtension(saveContainer.CheckFile, _FacePartsFilenameExtension)); + } + foreach (SaveContainer saveContainer in saveContainers) + { + if (string.IsNullOrEmpty(saveContainer.Directory) || string.IsNullOrEmpty(saveContainer.CheckFile) || saveContainer.ResizedFileHolder is not null || saveContainer.FaceFileHolder is not null || string.IsNullOrEmpty(saveContainer.Json)) + continue; + if (File.Exists(saveContainer.CheckFile)) + continue; + _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(saveContainer.CheckFile, saveContainer.Json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null); + } + foreach (SaveContainer saveContainer in saveContainers) + { + if (string.IsNullOrEmpty(saveContainer.Directory) || string.IsNullOrEmpty(saveContainer.CheckFile) || saveContainer.ResizedFileHolder is null) + continue; + if (string.IsNullOrEmpty(saveContainer.ShortcutFile) || !saveContainer.ResizedFileHolder.Exists) + continue; + try + { + windowsShortcut = new() { Path = saveContainer.ResizedFileHolder.FullName }; + windowsShortcut.Save(saveContainer.ShortcutFile); + windowsShortcut.Dispose(); + } + catch (Exception) + { } + } + } + + public void SaveNotMappedPersonKeys(string zPropertyHolderContentDirectory) + { + string directory; + SaveContainer saveContainer; + List saveContainers = new(); + const string facePopulatedKey = nameof(Closest); + foreach (string personKey in _NotMappedPersonKeys) + { + directory = Path.Combine(zPropertyHolderContentDirectory, $"{facePopulatedKey}NotMapped", personKey, Property.Models.Stateless.IResult.AllInOne); + saveContainer = new(directory); + saveContainers.Add(saveContainer); + } + SaveContainers(saveContainers); + } + public List<(Item, (string, Face?, (string, string, string, string))[])> GetCollection(List items, string dFacesContentDirectory) { List<(Item, (string, Face?, (string, string, string, string))[])> results = new(); @@ -508,110 +569,9 @@ public class MapLogic } } - private List<(IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile, string json)> GetClosest(string argZero, Container[] containers, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, string zPropertyHolderContentDirectory) + private List GetMappingSaveContainers(string argZero, Container[] containers, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, string zPropertyHolderContentDirectory) { - List<(IFileHolder?, string, FileInfo?, string, string, string)> results = new(); - Closest? match; - string dateKey; - string checkFile; - string directory; - string shortcutFile; - FileInfo faceFileInfo; - string? directoryName; - string facesDirectory; - string personDirectory; - List used = new(); - FileInfo landmarkFileInfo; - string landmarksDirectory; - double deterministicHashCodeKey; - DateTime dateTime = DateTime.Now; - const string facePopulatedKey = nameof(Closest); - foreach (Container container in containers) - { - if (!container.Items.Any()) - continue; - if (!container.SourceDirectory.StartsWith(argZero)) - continue; - foreach (Item item in container.Items) - { - used.Clear(); - if (item.ImageFileHolder is null || item.Property?.Id is null || item.ResizedFileHolder is null) - continue; - if (!item.Closest.Any()) - continue; - directoryName = Path.GetDirectoryName(item.RelativePath); - if (directoryName is null) - throw new Exception(); - foreach (Face face in item.Faces) - { - match = null; - if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) - continue; - foreach (Closest closest in item.Closest) - { - if (closest.NormalizedPixelPercentage != face.Location.NormalizedPixelPercentage.Value) - continue; - match = closest; - break; - } - if (match is null) - continue; - foreach (Mapping mapping in item.Mapping) - { - if (mapping.NormalizedPixelPercentage is null || mapping.NormalizedPixelPercentage.Value != face.Location.NormalizedPixelPercentage.Value) - continue; - throw new Exception(); - } - dateKey = Stateless.MapLogic.GetDateKey(dateTime, match.Mapping, match.MinimumDateTime, match.IsWrongYear); - directory = Path.Combine(zPropertyHolderContentDirectory, facePopulatedKey, match.Mapping.PersonKey, dateKey); - personDirectory = Path.Combine(directory, match.Mapping.DisplayDirectoryName[..1], "lnk"); - results.Add(new(null, personDirectory, null, string.Empty, string.Empty, string.Empty)); - facesDirectory = string.Concat(dFacesContentDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension)); - landmarksDirectory = string.Concat(d2ResultsFullGroupDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension)); - deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face); - 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 - shortcutFile = Path.Combine(personDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.lnk"); - results.Add(new(item.ResizedFileHolder, directory, faceFileInfo, checkFile, shortcutFile, string.Empty)); - personDirectory = Path.Combine(directory, match.Mapping.DisplayDirectoryName[..1], "lnk", match.Mapping.DisplayDirectoryName); - results.Add(new(null, personDirectory, null, string.Empty, string.Empty, string.Empty)); - used.Add(face.Location.NormalizedPixelPercentage.Value); - } - foreach (Closest closest in item.Closest) - { - if (used.Contains(closest.NormalizedPixelPercentage)) - continue; - dateKey = Stateless.MapLogic.GetDateKey(dateTime, closest.Mapping, closest.MinimumDateTime, closest.IsWrongYear); - directory = Path.Combine(zPropertyHolderContentDirectory, facePopulatedKey, closest.Mapping.PersonKey, dateKey); - personDirectory = Path.Combine(directory, closest.Mapping.DisplayDirectoryName, "lnk"); - results.Add(new(null, personDirectory, null, string.Empty, string.Empty, string.Empty)); - facesDirectory = string.Concat(dFacesContentDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension)); - landmarksDirectory = string.Concat(d2ResultsFullGroupDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension)); - deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.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 - shortcutFile = Path.Combine(personDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.lnk"); - results.Add(new(item.ResizedFileHolder, directory, faceFileInfo, checkFile, shortcutFile, string.Empty)); - personDirectory = Path.Combine(directory, closest.Mapping.DisplayDirectoryName[..1], "lnk", closest.Mapping.DisplayDirectoryName); - results.Add(new(null, personDirectory, null, string.Empty, string.Empty, string.Empty)); - used.Add(closest.NormalizedPixelPercentage); - } - } - } - return results; - } - - private List<(IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile, string json)> GetMapping(string argZero, Container[] containers, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, string zPropertyHolderContentDirectory) - { - List<(IFileHolder?, string, FileInfo?, string, string, string)> results = new(); + List results = new(); string key; string json; string dateKey; @@ -620,14 +580,16 @@ public class MapLogic string directory; bool? isWrongYear; string shortcutFile; - FileInfo faceFileInfo; string? directoryName; string facesDirectory; string personDirectory; List used = new(); DateTime minimumDateTime; - FileInfo landmarkFileInfo; - string landmarksDirectory; + FileHolder faceFileHolder; + string facePartsDirectory; + SaveContainer saveContainer; + FileHolder facePartsFileHolder; + FileHolder hiddenFaceFileHolder; double deterministicHashCodeKey; DateTime dateTime = DateTime.Now; const string facePopulatedKey = nameof(Mapping); @@ -677,26 +639,31 @@ public class MapLogic else directory = Path.Combine(zPropertyHolderContentDirectory, $"{facePopulatedKey}OutOfControl", match.PersonKey, dateKey); personDirectory = Path.Combine(directory, match.DisplayDirectoryName[..1], "lnk"); - results.Add(new(null, personDirectory, null, string.Empty, string.Empty, string.Empty)); + saveContainer = new(personDirectory); + results.Add(saveContainer); facesDirectory = string.Concat(dFacesContentDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension)); - landmarksDirectory = string.Concat(d2ResultsFullGroupDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension)); + facePartsDirectory = string.Concat(d2ResultsFullGroupDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension)); deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face); 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")); + faceFileHolder = new(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FacesFilenameExtension}")); + hiddenFaceFileHolder = new(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FacesHiddenFilenameExtension}")); + facePartsFileHolder = new(Path.Combine(facePartsDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FacePartsFilenameExtension}")); if (string.IsNullOrEmpty(personDirectory)) shortcutFile = string.Empty; else shortcutFile = Path.Combine(personDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.lnk"); - results.Add(new(item.ResizedFileHolder, directory, faceFileInfo, checkFile, shortcutFile, string.Empty)); + saveContainer = new(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, string.Empty, facePartsFileHolder, item.ResizedFileHolder, shortcutFile); + results.Add(saveContainer); if (!string.IsNullOrEmpty(checkFile) && Shared.Models.Stateless.IMapping.SaveFaceEncoding) { checkFile = Path.Combine(directory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.json"); json = JsonSerializer.Serialize(face.FaceEncoding); - results.Add(new(null, directory, null, checkFile, string.Empty, json)); + saveContainer = new(checkFile, directory, json); + results.Add(saveContainer); } personDirectory = Path.Combine(directory, match.DisplayDirectoryName[..1], "lnk", match.DisplayDirectoryName); - results.Add(new(null, personDirectory, null, string.Empty, string.Empty, string.Empty)); + saveContainer = new(personDirectory); + results.Add(saveContainer); used.Add(face.Location.NormalizedPixelPercentage.Value); } if (deterministicHashCodeKeyValuePairsAny && Shared.Models.Stateless.IMapping.UseDeterministicHashCodeUnknownFaceKeyValuePairsForSaveMapping) @@ -735,26 +702,31 @@ public class MapLogic else directory = Path.Combine(zPropertyHolderContentDirectory, $"{facePopulatedKey}WithButOutOfControl", match.PersonKey, dateKey); personDirectory = Path.Combine(directory, match.DisplayDirectoryName[..1], "lnk"); - results.Add(new(null, personDirectory, null, string.Empty, string.Empty, string.Empty)); + saveContainer = new(personDirectory); + results.Add(saveContainer); facesDirectory = string.Concat(dFacesContentDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension)); - landmarksDirectory = string.Concat(d2ResultsFullGroupDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension)); + facePartsDirectory = string.Concat(d2ResultsFullGroupDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension)); deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face); 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")); + faceFileHolder = new(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FacesFilenameExtension}")); + facePartsFileHolder = new(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FacesHiddenFilenameExtension}")); + facePartsFileHolder = new(Path.Combine(facePartsDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FacePartsFilenameExtension}")); if (string.IsNullOrEmpty(personDirectory)) shortcutFile = string.Empty; else shortcutFile = Path.Combine(personDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.lnk"); - results.Add(new(item.ResizedFileHolder, directory, faceFileInfo, checkFile, shortcutFile, string.Empty)); + saveContainer = new(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, string.Empty, facePartsFileHolder, item.ResizedFileHolder, shortcutFile); + results.Add(saveContainer); if (!string.IsNullOrEmpty(checkFile) && Shared.Models.Stateless.IMapping.SaveFaceEncoding) { checkFile = Path.Combine(directory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.json"); json = JsonSerializer.Serialize(face.FaceEncoding); - results.Add(new(null, directory, null, checkFile, string.Empty, json)); + saveContainer = new(checkFile, directory, json); + results.Add(saveContainer); } personDirectory = Path.Combine(directory, match.DisplayDirectoryName[..1], "lnk", match.DisplayDirectoryName); - results.Add(new(null, personDirectory, null, string.Empty, string.Empty, string.Empty)); + saveContainer = new(personDirectory); + results.Add(saveContainer); used.Add(face.Location.NormalizedPixelPercentage.Value); } } @@ -763,63 +735,127 @@ public class MapLogic return results; } - private static void Save(List<(IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile, string json)> collection) + private List GetClosestSaveContainers(string argZero, Container[] containers, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, string zPropertyHolderContentDirectory) { - WindowsShortcut windowsShortcut; - string[] directories = (from l in collection select l.directory).Distinct().ToArray(); - foreach (string directory in directories) + List results = new(); + Closest? match; + string dateKey; + string checkFile; + string directory; + string shortcutFile; + string? directoryName; + string facesDirectory; + string personDirectory; + List used = new(); + FileHolder faceFileHolder; + string facePartsDirectory; + SaveContainer saveContainer; + FileHolder facePartsFileHolder; + FileHolder hiddenFaceFileHolder; + double deterministicHashCodeKey; + DateTime dateTime = DateTime.Now; + const string facePopulatedKey = nameof(Closest); + foreach (Container container in containers) { - if (string.IsNullOrEmpty(directory)) + if (!container.Items.Any()) continue; - if (!Directory.Exists(directory)) - _ = Directory.CreateDirectory(directory); - } - foreach ((IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile, string json) in collection) - { - if (string.IsNullOrEmpty(directory) || string.IsNullOrEmpty(checkFile) || resizedFileHolder is null || faceFileInfo is null || !string.IsNullOrEmpty(json)) + if (!container.SourceDirectory.StartsWith(argZero)) continue; - if (File.Exists(checkFile)) - continue; - if (faceFileInfo.Directory is not null && faceFileInfo.Directory.Exists && faceFileInfo.Exists) - File.Copy(faceFileInfo.FullName, checkFile); - else - File.Copy(resizedFileHolder.FullName, checkFile); - } - foreach ((IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile, string json) in collection) - { - if (string.IsNullOrEmpty(directory) || string.IsNullOrEmpty(checkFile) || resizedFileHolder is not null || faceFileInfo is not null || string.IsNullOrEmpty(json)) - continue; - if (File.Exists(checkFile)) - continue; - _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(checkFile, json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null); - } - foreach ((IFileHolder? resizedFileHolder, string directory, FileInfo? _, string checkFile, string shortcutFile, string json) in collection) - { - if (string.IsNullOrEmpty(directory) || string.IsNullOrEmpty(checkFile) || resizedFileHolder is null) - continue; - if (string.IsNullOrEmpty(shortcutFile) || !resizedFileHolder.Exists) - continue; - try + foreach (Item item in container.Items) { - windowsShortcut = new() { Path = resizedFileHolder.FullName }; - windowsShortcut.Save(shortcutFile); - windowsShortcut.Dispose(); + used.Clear(); + if (item.ImageFileHolder is null || item.Property?.Id is null || item.ResizedFileHolder is null) + continue; + if (!item.Closest.Any()) + continue; + directoryName = Path.GetDirectoryName(item.RelativePath); + if (directoryName is null) + throw new Exception(); + foreach (Face face in item.Faces) + { + match = null; + if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) + continue; + foreach (Closest closest in item.Closest) + { + if (closest.NormalizedPixelPercentage != face.Location.NormalizedPixelPercentage.Value) + continue; + match = closest; + break; + } + if (match is null) + continue; + foreach (Mapping mapping in item.Mapping) + { + if (mapping.NormalizedPixelPercentage is null || mapping.NormalizedPixelPercentage.Value != face.Location.NormalizedPixelPercentage.Value) + continue; + throw new Exception(); + } + dateKey = Stateless.MapLogic.GetDateKey(dateTime, match.Mapping, match.MinimumDateTime, match.IsWrongYear); + directory = Path.Combine(zPropertyHolderContentDirectory, facePopulatedKey, match.Mapping.PersonKey, dateKey); + personDirectory = Path.Combine(directory, match.Mapping.DisplayDirectoryName[..1], "lnk"); + saveContainer = new(personDirectory); + results.Add(saveContainer); + facesDirectory = string.Concat(dFacesContentDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension)); + facePartsDirectory = string.Concat(d2ResultsFullGroupDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension)); + deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, face); + checkFile = Path.Combine(directory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}"); + faceFileHolder = new(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FacesFilenameExtension}")); + hiddenFaceFileHolder = new(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FacesHiddenFilenameExtension}")); + facePartsFileHolder = new(Path.Combine(facePartsDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FacePartsFilenameExtension}")); + if (string.IsNullOrEmpty(personDirectory)) + shortcutFile = string.Empty; + else + shortcutFile = Path.Combine(personDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.lnk"); + saveContainer = new(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, string.Empty, facePartsFileHolder, item.ResizedFileHolder, shortcutFile); + results.Add(saveContainer); + personDirectory = Path.Combine(directory, match.Mapping.DisplayDirectoryName[..1], "lnk", match.Mapping.DisplayDirectoryName); + saveContainer = new(personDirectory); + results.Add(saveContainer); + used.Add(face.Location.NormalizedPixelPercentage.Value); + } + foreach (Closest closest in item.Closest) + { + if (used.Contains(closest.NormalizedPixelPercentage)) + continue; + dateKey = Stateless.MapLogic.GetDateKey(dateTime, closest.Mapping, closest.MinimumDateTime, closest.IsWrongYear); + directory = Path.Combine(zPropertyHolderContentDirectory, facePopulatedKey, closest.Mapping.PersonKey, dateKey); + personDirectory = Path.Combine(directory, closest.Mapping.DisplayDirectoryName, "lnk"); + saveContainer = new(personDirectory); + results.Add(saveContainer); + facesDirectory = string.Concat(dFacesContentDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension)); + facePartsDirectory = string.Concat(d2ResultsFullGroupDirectory, Path.Combine(directoryName, item.ImageFileHolder.NameWithoutExtension)); + deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(item, closest); + checkFile = Path.Combine(directory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}"); + faceFileHolder = new(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FacesFilenameExtension}")); + hiddenFaceFileHolder = new(Path.Combine(facesDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FacesHiddenFilenameExtension}")); + facePartsFileHolder = new(Path.Combine(facePartsDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}{_FacePartsFilenameExtension}")); + if (string.IsNullOrEmpty(personDirectory)) + shortcutFile = string.Empty; + else + shortcutFile = Path.Combine(personDirectory, $"{deterministicHashCodeKey}{item.ImageFileHolder.ExtensionLowered}.lnk"); + saveContainer = new(checkFile, directory, faceFileHolder, hiddenFaceFileHolder, string.Empty, facePartsFileHolder, item.ResizedFileHolder, shortcutFile); + results.Add(saveContainer); + personDirectory = Path.Combine(directory, closest.Mapping.DisplayDirectoryName[..1], "lnk", closest.Mapping.DisplayDirectoryName); + saveContainer = new(personDirectory); + results.Add(saveContainer); + used.Add(closest.NormalizedPixelPercentage); + } } - catch (Exception) - { } } - } - - public void SaveClosest(string argZero, Container[] containers, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, string zPropertyHolderContentDirectory) - { - List<(IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile, string json)> collection = GetClosest(argZero, containers, dFacesContentDirectory, d2ResultsFullGroupDirectory, zPropertyHolderContentDirectory); - Save(collection); + return results; } public void SaveMapping(string argZero, Container[] containers, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, string zPropertyHolderContentDirectory) { - List<(IFileHolder? resizedFileHolder, string directory, FileInfo? faceFileInfo, string checkFile, string shortcutFile, string json)> collection = GetMapping(argZero, containers, dFacesContentDirectory, d2ResultsFullGroupDirectory, zPropertyHolderContentDirectory); - Save(collection); + List saveContainers = GetMappingSaveContainers(argZero, containers, dFacesContentDirectory, d2ResultsFullGroupDirectory, zPropertyHolderContentDirectory); + SaveContainers(saveContainers); + } + + public void SaveClosest(string argZero, Container[] containers, string dFacesContentDirectory, string d2ResultsFullGroupDirectory, string zPropertyHolderContentDirectory) + { + List saveContainers = GetClosestSaveContainers(argZero, containers, dFacesContentDirectory, d2ResultsFullGroupDirectory, zPropertyHolderContentDirectory); + SaveContainers(saveContainers); } } \ No newline at end of file diff --git a/Map/Models/Stateless/IMapLogic.cs b/Map/Models/Stateless/IMapLogic.cs index 846fbbe..9cde492 100644 --- a/Map/Models/Stateless/IMapLogic.cs +++ b/Map/Models/Stateless/IMapLogic.cs @@ -7,6 +7,10 @@ public interface IMapLogic static (bool?, string[]) IsWrongYear(Shared.Models.Item item) => MapLogic.IsWrongYear(item); + void TestStatic_SetSingleImage(string[] ignoreRelativePaths, string argZero, Shared.Models.Container[] containers); + static void SetSingleImage(string[] ignoreRelativePaths, string argZero, Shared.Models.Container[] containers) => + MapLogic.SetSingleImage(ignoreRelativePaths, argZero, containers); + string TestStatic_GetDateKey(DateTime dateTime, Shared.Models.Mapping mapping, DateTime minimumDateTime, bool? isWrongYear); static string GetDateKey(DateTime dateTime, Shared.Models.Mapping mapping, DateTime minimumDateTime, bool? isWrongYear) => MapLogic.GetDateKey(dateTime, mapping, minimumDateTime, isWrongYear); diff --git a/Map/Models/Stateless/MapLogic.cs b/Map/Models/Stateless/MapLogic.cs index 675f810..4679fd8 100644 --- a/Map/Models/Stateless/MapLogic.cs +++ b/Map/Models/Stateless/MapLogic.cs @@ -1,4 +1,5 @@ using View_by_Distance.Shared.Models; +using View_by_Distance.Shared.Models.Stateless; namespace View_by_Distance.Map.Models.Stateless; @@ -90,4 +91,44 @@ internal abstract class MapLogic return result; } + internal static void SetSingleImage(string[] ignoreRelativePaths, string argZero, Container[] containers) + { + Mapping mapping; + string personKey; + int? approximateYears = null; + PersonBirthday? personBirthday = null; + const string displayDirectoryName = Property.Models.Stateless.IResult.AllInOne; + foreach (Container container in containers) + { + if (!container.Items.Any()) + continue; + if (!container.SourceDirectory.StartsWith(argZero)) + continue; + if (ignoreRelativePaths.Contains(Path.GetFileName(container.SourceDirectory))) + continue; + foreach (Item item in container.Items) + { + if (item.ImageFileHolder is null || item.Property?.Id is null) + continue; + foreach (Face face in item.Faces) + { + if (face.FaceEncoding is null || face.Location?.NormalizedPixelPercentage is null) + continue; + personKey = DateTime.MinValue.AddYears(IPersonBirthday.FirstYear).ToString(IPersonBirthday.Format); + personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKey); + if (personBirthday is null) + continue; + mapping = new(approximateYears, displayDirectoryName, face.Location.NormalizedPixelPercentage, personBirthday, personKey); + item.Mapping.Add(mapping); + if (personBirthday is not null) + break; + } + if (personBirthday is not null) + break; + } + if (personBirthday is not null) + break; + } + } + } \ No newline at end of file diff --git a/Map/Models/Stateless/SetByDeterministicHashCode.cs b/Map/Models/Stateless/SetByDeterministicHashCode.cs index e3def39..766ce34 100644 --- a/Map/Models/Stateless/SetByDeterministicHashCode.cs +++ b/Map/Models/Stateless/SetByDeterministicHashCode.cs @@ -7,7 +7,7 @@ namespace View_by_Distance.Map.Models.Stateless; public class ByDeterministicHashCode { - private static void SetOther(string outputExtension, Dictionary personKeyValuePairs, string deterministicHashCodePeopleDirectory, List skipCollection, List<(string, int?, string, PersonBirthday[])> peopleCollection) + private static void SetOther(string resizeFilenameExtension, Person[] people, string deterministicHashCodePeopleDirectory, List skipCollection, List<(string, int?, string, PersonBirthday[])> peopleCollection) { string json; string personKey; @@ -18,22 +18,31 @@ public class ByDeterministicHashCode string[] personKeyDirectories; string personKeyJsonDirectory; PersonBirthday? personBirthday; + List personKeys = new(); string[] personDisplayDirectories; string convertedPersonKeyDirectory; string? personDisplayDirectoryName; List personBirthdays; + Dictionary personKeyValuePairs = new(); + foreach (Person person in people) + { + personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(person.Birthday); + if (personKeyValuePairs.ContainsKey(personKey)) + break; + personKeyValuePairs.Add(personKey, person); + } string[] groupDirectories = Directory.GetDirectories(deterministicHashCodePeopleDirectory, "*", SearchOption.TopDirectoryOnly); foreach (string groupDirectory in groupDirectories) { groupDirectoryName = Path.GetFileName(groupDirectory); if (groupDirectoryName[0] == '!') { - skipCollection.AddRange(from l in Directory.GetFiles(groupDirectory, $"*{outputExtension}", SearchOption.AllDirectories) select double.Parse(Path.GetFileNameWithoutExtension(l))); + skipCollection.AddRange(from l in Directory.GetFiles(groupDirectory, $"*{resizeFilenameExtension}", SearchOption.AllDirectories) select double.Parse(Path.GetFileNameWithoutExtension(l))); continue; } else if (groupDirectoryName[0] is not '_' and not '~' and not '^') continue; - skipCollection.AddRange(from l in Directory.GetFiles(groupDirectory, $"*{outputExtension}", SearchOption.AllDirectories) select double.Parse(Path.GetFileNameWithoutExtension(l))); + skipCollection.AddRange(from l in Directory.GetFiles(groupDirectory, $"*{resizeFilenameExtension}", SearchOption.AllDirectories) select double.Parse(Path.GetFileNameWithoutExtension(l))); personDisplayDirectories = Directory.GetDirectories(groupDirectory, "*", SearchOption.TopDirectoryOnly); foreach (string personDisplayDirectory in personDisplayDirectories) { @@ -84,10 +93,24 @@ public class ByDeterministicHashCode json = JsonSerializer.Serialize(personKeyValuePairs[personKey], new JsonSerializerOptions() { WriteIndented = true }); _ = Shared.Models.Stateless.Methods.IPath.WriteAllText(personKeyJsonFileName, json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null); } + personKeys.Add(personKey); peopleCollection.Add(new(personDisplayDirectoryName, approximateYears, personKey, personBirthdays.OrderByDescending(l => l.Value).ToArray())); } } } + approximateYears = null; + const string displayDirectoryName = Property.Models.Stateless.IResult.AllInOne; + DateTime incrementDate = new(Shared.Models.Stateless.IPersonBirthday.FirstYear, 1, 1); + for (int i = 0; i < 500; i++) + { + incrementDate = incrementDate.AddDays(1); + personBirthday = new(incrementDate); + personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthday); + if (personKeys.Contains(personKey)) + continue; + personKeys.Add(personKey); + peopleCollection.Add(new(displayDirectoryName, approximateYears, personKey, new PersonBirthday[] { personBirthday })); + } } internal static void SetKeyValuePairs(string deterministicHashCodeContentDirectory, List<(string, double)> deterministicHashCodeCollection, List<(string, double)> incorrectDeterministicHashCodeCollection, Dictionary> keyValuePairs) @@ -138,8 +161,6 @@ public class ByDeterministicHashCode continue; deterministicHashCodeCollection.Add(new(personKey, reversedDeterministicHashCodeKey.Value)); } - if (personNameDirectory == personFirstInitialDirectory) - continue; personNameLinkDirectories = Directory.GetDirectories(personNameDirectory, "*", SearchOption.TopDirectoryOnly); foreach (string personNameLinkDirectory in personNameLinkDirectories) { @@ -152,6 +173,8 @@ public class ByDeterministicHashCode } _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(personNameLinkDirectory); } + if (personNameDirectory == personFirstInitialDirectory) + continue; Directory.Move(personNameDirectory, personFirstInitialDirectory); _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(personNameDirectory); } @@ -163,56 +186,90 @@ public class ByDeterministicHashCode } } - internal static string SetByRef(string outputExtension, Dictionary personKeyValuePairs, List skipCollection, Dictionary peopleKeyValuePairs, Dictionary deterministicHashCodeUnknownFaceKeyValuePairs, Dictionary deterministicHashCodeKeyValuePairs, Dictionary incorrectDeterministicHashCodeKeyValuePairs, string deterministicHashCodeRootDirectory) + internal static string SetByRef(string resizeFilenameExtension, Person[] people, List skipCollection, Dictionary peopleKeyValuePairs, List notMappedPersonKeys, Dictionary deterministicHashCodeUnknownFaceKeyValuePairs, Dictionary deterministicHashCodeKeyValuePairs, Dictionary incorrectDeterministicHashCodeKeyValuePairs, string deterministicHashCodeRootDirectory) { string result; + string[] distinctPersonKeys; + Dictionary> keyValuePairs = new(); List deterministicHashCodePersonKeys = new(); List deterministicHashCodeUnknownFacePersonKeys = new(); + Dictionary> deterministicHashCodeScope = new(); + Dictionary> incorrectDeterministicHashCodeScope = new(); + List<(string PersonKey, double IdAndNormalizedPixelPercentage)> deterministicHashCodeCollection = new(); + string deterministicHashCodePeopleDirectory = Path.Combine(deterministicHashCodeRootDirectory, "People"); + List<(string PersonKey, double IdAndNormalizedPixelPercentage)> incorrectDeterministicHashCodeCollection = new(); foreach (KeyValuePair keyValuePair in deterministicHashCodeUnknownFaceKeyValuePairs) deterministicHashCodeUnknownFacePersonKeys.AddRange(keyValuePair.Value); deterministicHashCodeUnknownFacePersonKeys = deterministicHashCodeUnknownFacePersonKeys.Distinct().ToList(); List<(string, int?, string, PersonBirthday[])> peopleCollection = new(); - string deterministicHashCodePeopleDirectory = Path.Combine(deterministicHashCodeRootDirectory, "People"); - if (Directory.Exists(deterministicHashCodePeopleDirectory)) - SetOther(outputExtension, personKeyValuePairs, deterministicHashCodePeopleDirectory, skipCollection, peopleCollection); + if (!Directory.Exists(deterministicHashCodePeopleDirectory)) + _ = Directory.CreateDirectory(deterministicHashCodePeopleDirectory); + else + SetOther(resizeFilenameExtension, people, deterministicHashCodePeopleDirectory, skipCollection, peopleCollection); result = Path.Combine(deterministicHashCodeRootDirectory, "()"); if (!Directory.Exists(result)) - result = string.Empty; - else + _ = Directory.CreateDirectory(result); + SetKeyValuePairs(result, deterministicHashCodeCollection, incorrectDeterministicHashCodeCollection, keyValuePairs); + deterministicHashCodeCollection = (from l in deterministicHashCodeCollection orderby l.IdAndNormalizedPixelPercentage select l).ToList(); + incorrectDeterministicHashCodeCollection = (from l in incorrectDeterministicHashCodeCollection orderby l.IdAndNormalizedPixelPercentage select l).ToList(); + foreach ((string personKey, double idAndNormalizedPixelPercentage) in deterministicHashCodeCollection) { - Dictionary> keyValuePairs = new(); - Dictionary> deterministicHashCodeScope = new(); - Dictionary> incorrectDeterministicHashCodeScope = new(); - List<(string PersonKey, double IdAndNormalizedPixelPercentage)> deterministicHashCodeCollection = new(); - List<(string PersonKey, double IdAndNormalizedPixelPercentage)> incorrectDeterministicHashCodeCollection = new(); - SetKeyValuePairs(result, deterministicHashCodeCollection, incorrectDeterministicHashCodeCollection, keyValuePairs); - deterministicHashCodeCollection = (from l in deterministicHashCodeCollection orderby l.IdAndNormalizedPixelPercentage select l).ToList(); - incorrectDeterministicHashCodeCollection = (from l in incorrectDeterministicHashCodeCollection orderby l.IdAndNormalizedPixelPercentage select l).ToList(); - foreach ((string personKey, double idAndNormalizedPixelPercentage) in deterministicHashCodeCollection) - { - if (!deterministicHashCodeScope.ContainsKey(idAndNormalizedPixelPercentage)) - deterministicHashCodeScope.Add(idAndNormalizedPixelPercentage, new()); - deterministicHashCodeScope[idAndNormalizedPixelPercentage].Add(personKey); - deterministicHashCodePersonKeys.Add(personKey); - } - deterministicHashCodePersonKeys = deterministicHashCodePersonKeys.Distinct().ToList(); - foreach ((string personKey, double idAndNormalizedPixelPercentage) in incorrectDeterministicHashCodeCollection) - { - if (!incorrectDeterministicHashCodeScope.ContainsKey(idAndNormalizedPixelPercentage)) - incorrectDeterministicHashCodeScope.Add(idAndNormalizedPixelPercentage, new()); - incorrectDeterministicHashCodeScope[idAndNormalizedPixelPercentage].Add(personKey); - } - foreach (KeyValuePair> keyValuePair in deterministicHashCodeScope) - deterministicHashCodeKeyValuePairs.Add(keyValuePair.Key, keyValuePair.Value.Distinct().ToArray()); - foreach (KeyValuePair> keyValuePair in incorrectDeterministicHashCodeScope) - incorrectDeterministicHashCodeKeyValuePairs.Add(keyValuePair.Key, keyValuePair.Value.Distinct().ToArray()); + if (!deterministicHashCodeScope.ContainsKey(idAndNormalizedPixelPercentage)) + deterministicHashCodeScope.Add(idAndNormalizedPixelPercentage, new()); + deterministicHashCodeScope[idAndNormalizedPixelPercentage].Add(personKey); + deterministicHashCodePersonKeys.Add(personKey); } - foreach ((string personDisplayDirectoryName, int? approximateYears, string personKey, PersonBirthday[] personBirthdays) in peopleCollection) + deterministicHashCodePersonKeys = deterministicHashCodePersonKeys.Distinct().ToList(); + foreach ((string personKey, double idAndNormalizedPixelPercentage) in incorrectDeterministicHashCodeCollection) { - if (peopleKeyValuePairs.ContainsKey(personKey) && peopleKeyValuePairs[personKey].Item1 != personDisplayDirectoryName) - throw new NotImplementedException(); - if (deterministicHashCodeUnknownFacePersonKeys.Contains(personKey) || deterministicHashCodePersonKeys.Contains(personKey)) - peopleKeyValuePairs.Add(personKey, new(personDisplayDirectoryName, approximateYears, personKey, personBirthdays)); + if (!incorrectDeterministicHashCodeScope.ContainsKey(idAndNormalizedPixelPercentage)) + incorrectDeterministicHashCodeScope.Add(idAndNormalizedPixelPercentage, new()); + incorrectDeterministicHashCodeScope[idAndNormalizedPixelPercentage].Add(personKey); + } + foreach (KeyValuePair> keyValuePair in deterministicHashCodeScope) + { + distinctPersonKeys = keyValuePair.Value.Distinct().ToArray(); + deterministicHashCodeKeyValuePairs.Add(keyValuePair.Key, distinctPersonKeys); + } + foreach (KeyValuePair> keyValuePair in incorrectDeterministicHashCodeScope) + incorrectDeterministicHashCodeKeyValuePairs.Add(keyValuePair.Key, keyValuePair.Value.Distinct().ToArray()); + if (peopleCollection.Any()) + { + foreach ((string displayDirectoryName, int? approximateYears, string personKey, PersonBirthday[] personBirthdays) in peopleCollection) + { + if (peopleKeyValuePairs.ContainsKey(personKey) && peopleKeyValuePairs[personKey].Item1 != displayDirectoryName) + throw new NotImplementedException(); + if (deterministicHashCodeUnknownFacePersonKeys.Contains(personKey) || deterministicHashCodePersonKeys.Contains(personKey)) + peopleKeyValuePairs.Add(personKey, new(displayDirectoryName, approximateYears, personKey, personBirthdays)); + else + notMappedPersonKeys.Add(personKey); + } + } + if (deterministicHashCodeUnknownFacePersonKeys.Any() || deterministicHashCodePersonKeys.Any()) + { + int? approximateYears = null; + PersonBirthday? personBirthday; + const string displayDirectoryName = Property.Models.Stateless.IResult.AllInOne; + foreach (string personKey in deterministicHashCodeUnknownFacePersonKeys) + { + if (!peopleKeyValuePairs.ContainsKey(personKey)) + { + personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKey); + if (personBirthday is null) + continue; + peopleKeyValuePairs.Add(personKey, new(displayDirectoryName, approximateYears, personKey, new PersonBirthday[] { personBirthday })); + } + } + foreach (string personKey in deterministicHashCodePersonKeys) + { + if (!peopleKeyValuePairs.ContainsKey(personKey)) + { + personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKey); + if (personBirthday is null) + continue; + peopleKeyValuePairs.Add(personKey, new(displayDirectoryName, approximateYears, personKey, new PersonBirthday[] { personBirthday })); + } + } } return result; } diff --git a/Property/Models/A_Property.cs b/Property/Models/A_Property.cs index 7986100..5cae985 100644 --- a/Property/Models/A_Property.cs +++ b/Property/Models/A_Property.cs @@ -114,6 +114,10 @@ public class A_Property Shared.Models.Property result; if (_Log is null) throw new NullReferenceException(nameof(_Log)); + if (filteredSourceDirectoryFileHolder.CreationTime is null) + throw new NullReferenceException(nameof(filteredSourceDirectoryFileHolder.CreationTime)); + if (filteredSourceDirectoryFileHolder.LastWriteTime is null) + throw new NullReferenceException(nameof(filteredSourceDirectoryFileHolder.LastWriteTime)); long ticks; byte[] bytes; string value; @@ -275,7 +279,7 @@ public class A_Property 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); + result = new(filteredSourceDirectoryFileHolder.CreationTime.Value, dateTime, dateTimeDigitized, dateTimeOriginal, fileLength, gpsDateStamp, height, id, indices.ToArray(), filteredSourceDirectoryFileHolder.LastWriteTime.Value, make, model, orientation, width); return result; } diff --git a/Property/Models/Stateless/Container.cs b/Property/Models/Stateless/Container.cs index 47d9f87..4a2ac9d 100644 --- a/Property/Models/Stateless/Container.cs +++ b/Property/Models/Stateless/Container.cs @@ -147,19 +147,15 @@ public class Container private static Shared.Models.Container[] GetContainers(Configuration configuration, bool firstRun, string aPropertySingletonDirectory, List<(int, string, FileHolder[], int)> fileHolderGroupCollection, List<(int, string, List<(string, Shared.Models.Property?)>, int)> collectionFromJson) { Shared.Models.Container[] results; + Item item; int length; int additional; string inferred; - string fileName; - string extension; List items; string[] existing; string keyWithJson; string relativePath; - string? directoryName; - string extensionLowered; FileHolder keyFileHolder; - string? fileNameWithoutExtension; bool isValidImageFormatExtension; Shared.Models.Container container; List keySourceDirectories; @@ -170,22 +166,8 @@ public class Container { foreach (FileHolder sourceDirectoryFileHolder in sourceDirectoryFileHolderCollection) { - relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(sourceDirectoryFileHolder.FullName, length); + relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(sourceDirectoryFileHolder.FullName, length, forceExtensionToLower: true); fileHolderKeyValuePairs.Add(relativePath, new(sourceDirectory, sourceDirectoryFileHolder)); - extension = Path.GetExtension(sourceDirectoryFileHolder.FullName); - extensionLowered = Path.GetExtension(sourceDirectoryFileHolder.FullName).ToLower(); - if (extension != extensionLowered) - { - directoryName = Path.GetDirectoryName(sourceDirectoryFileHolder.FullName); - if (string.IsNullOrEmpty(directoryName)) - continue; - fileNameWithoutExtension = Path.GetFileNameWithoutExtension(sourceDirectoryFileHolder.FullName); - if (string.IsNullOrEmpty(fileNameWithoutExtension)) - continue; - fileName = Path.Combine(directoryName, $"{fileNameWithoutExtension}{extensionLowered}"); - relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(fileName, length); - fileHolderKeyValuePairs.Add(relativePath, new(sourceDirectory, sourceDirectoryFileHolder)); - } } } length = aPropertySingletonDirectory.Length; @@ -197,7 +179,7 @@ public class Container keySourceDirectories = new(); foreach ((string sourceDirectoryFile, Shared.Models.Property? property) in collection) { - keyWithJson = Shared.Models.Stateless.Methods.IPath.GetRelativePath(sourceDirectoryFile, length); + keyWithJson = Shared.Models.Stateless.Methods.IPath.GetRelativePath(sourceDirectoryFile, length, forceExtensionToLower: false); relativePath = keyWithJson[..^5]; if (!fileHolderKeyValuePairs.ContainsKey(relativePath)) { @@ -207,7 +189,8 @@ public class Container continue; keySourceDirectories.Add(string.Concat(keyFileHolder.DirectoryName)); isValidImageFormatExtension = configuration.ValidImageFormatExtensions.Contains(keyFileHolder.ExtensionLowered); - items.Add(new(sourceDirectoryFile, relativePath, keyFileHolder, isValidImageFormatExtension, property, true, null)); + item = new(sourceDirectoryFile, relativePath, keyFileHolder, isValidImageFormatExtension, property, true, null); + items.Add(item); } else { @@ -219,11 +202,12 @@ public class Container continue; 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)); + item = new(sourceDirectoryFile, relativePath, keyFileHolder, isValidImageFormatExtension, property, false, null); else if (configuration.PropertiesChangedForProperty || property.LastWriteTime != keyFileHolder.LastWriteTime || property.FileSize != keyFileHolder.Length) - items.Add(new(sourceDirectoryFile, relativePath, keyFileHolder, isValidImageFormatExtension, property, false, true)); + item = new(sourceDirectoryFile, relativePath, keyFileHolder, isValidImageFormatExtension, property, false, true); else - items.Add(new(sourceDirectoryFile, relativePath, keyFileHolder, isValidImageFormatExtension, property, false, false)); + item = new(sourceDirectoryFile, relativePath, keyFileHolder, isValidImageFormatExtension, property, false, false); + items.Add(item); } } if (items.Any()) @@ -240,7 +224,7 @@ public class Container items = new(); foreach (FileHolder sourceDirectoryFileHolder in sourceDirectoryFileHolderCollection) { - relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(sourceDirectoryFileHolder.FullName, length); + relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(sourceDirectoryFileHolder.FullName, length, forceExtensionToLower: true); if (!fileHolderKeyValuePairs.ContainsKey(relativePath)) continue; if (!fileHolderKeyValuePairs.Remove(relativePath)) @@ -248,7 +232,13 @@ public class Container if (sourceDirectoryFileHolder.ExtensionLowered is ".json") continue; isValidImageFormatExtension = configuration.ValidImageFormatExtensions.Contains(sourceDirectoryFileHolder.ExtensionLowered); - items.Add(new(relativePath, sourceDirectoryFileHolder.FullName, sourceDirectoryFileHolder, isValidImageFormatExtension, null, null, null)); + if (firstRun) + item = new(sourceDirectoryFileHolder.FullName, relativePath, sourceDirectoryFileHolder, isValidImageFormatExtension, null, null, null); + else if (!isValidImageFormatExtension) + item = new(sourceDirectoryFileHolder.FullName, relativePath, sourceDirectoryFileHolder, isValidImageFormatExtension, null, null, null); + else + item = new(sourceDirectoryFileHolder.FullName, relativePath, sourceDirectoryFileHolder, isValidImageFormatExtension, null, null, null); + items.Add(item); } if (items.Any()) { @@ -261,9 +251,11 @@ public class Container { additional = 0; container = keyValuePairs[sourceDirectory]; + length = items.Count; existing = (from l in container.Items select l.ImageFileHolder?.FullName).ToArray(); - foreach (Item item in items) + for (int i = 0; i < length; i++) { + item = items[i]; if (item.ImageFileHolder is null || existing.Contains(item.ImageFileHolder.FullName)) continue; additional += 1; diff --git a/Resize/Models/_C_Resize.cs b/Resize/Models/_C_Resize.cs index 4a436ad..84842a8 100644 --- a/Resize/Models/_C_Resize.cs +++ b/Resize/Models/_C_Resize.cs @@ -1,6 +1,5 @@ using System.Drawing; using System.Drawing.Imaging; -using System.Globalization; using System.Reflection; using System.Runtime.InteropServices; using System.Text; @@ -164,12 +163,16 @@ public class C_Resize } } - private byte[] SaveResizedSubfile3(string subFile, int[] resize, byte[] bytes, Shared.Models.FileHolder? fileHolder) + private byte[] SaveResizedSubfile3(Shared.Models.Item item, int[] resize, bool returnAndDoNotWrite, byte[] bytes) { + if (item.ImageFileHolder is null) + throw new NullReferenceException(nameof(item.ImageFileHolder)); + if (item.ResizedFileHolder is null) + throw new NullReferenceException(nameof(item.ResizedFileHolder)); byte[] results; Bitmap bitmap; int outputResolutionWidth = resize[_OutputResolutionWidthIndex]; - using Bitmap temp = new(subFile, useIcm: false); + using Bitmap temp = new(item.ImageFileHolder.FullName, useIcm: false); int outputResolutionHeight = resize[_OutputResolutionHeightIndex]; PropertyItem[] propertyItems = temp.PropertyItems; int outputResolutionOrientation = resize[_OutputResolutionOrientationIndex]; @@ -204,23 +207,27 @@ public class C_Resize default: break; } - if (fileHolder is null) + if (returnAndDoNotWrite) results = GetBitmapData(bitmap); else { results = Array.Empty(); CopyPropertyItems(bytes, propertyItems, bitmap); - bitmap.Save(fileHolder.FullName, _ImageCodecInfo, _EncoderParameters); + bitmap.Save(item.ResizedFileHolder.FullName, _ImageCodecInfo, _EncoderParameters); } bitmap.Dispose(); return results; } - private byte[] SaveResizedSubfile5(string subFile, int[] resize, byte[] bytes, Shared.Models.FileHolder? fileHolder) + private byte[] SaveResizedSubfile5(Shared.Models.Item item, int[] resize, bool returnAndDoNotWrite, byte[] bytes) { + if (item.ImageFileHolder is null) + throw new NullReferenceException(nameof(item.ImageFileHolder)); + if (item.ResizedFileHolder is null) + throw new NullReferenceException(nameof(item.ResizedFileHolder)); byte[] results; Bitmap bitmap; - using Bitmap temp = new(subFile, useIcm: false); + using Bitmap temp = new(item.ImageFileHolder.FullName, useIcm: false); PropertyItem[] propertyItems = temp.PropertyItems; int tempResolutionWidth = resize[_TempResolutionWidth]; int tempResolutionHeight = resize[_TempResolutionHeight]; @@ -268,13 +275,13 @@ public class C_Resize { using (Graphics graphics = Graphics.FromImage(preRotated)) graphics.DrawImage(bitmap, new Rectangle(0, 0, outputResolutionWidth, outputResolutionHeight), rectangle, GraphicsUnit.Pixel); - if (fileHolder is null) + if (returnAndDoNotWrite) results = GetBitmapData(bitmap); else { results = Array.Empty(); CopyPropertyItems(bytes, propertyItems, bitmap); - bitmap.Save(fileHolder.FullName, _ImageCodecInfo, _EncoderParameters); + bitmap.Save(item.ResizedFileHolder.FullName, _ImageCodecInfo, _EncoderParameters); } } bitmap.Dispose(); @@ -283,54 +290,37 @@ public class C_Resize #pragma warning restore CA1416 - private byte[] SaveResizedSubfile(string subFile, Shared.Models.Property property, int[] resize, Shared.Models.FileHolder? fileHolder) + private byte[] SaveResizedSubfile(Shared.Models.Item item, int[] resize, bool returnAndDoNotWrite) { + if (item.Property is null) + throw new NullReferenceException(nameof(item.Property)); byte[] results; + // string subFile, Shared.Models.Property property, Shared.Models.FileHolder? fileHolder string dateTimeFormat = Shared.Models.Stateless.Methods.IProperty.DateTimeFormat(); - DateTime dateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(property); + DateTime dateTime = Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(item.Property); string dateTimeValue = dateTime.ToString(dateTimeFormat); byte[] bytes = _ASCIIEncoding.GetBytes(dateTimeValue); if (_ASCIIEncoding.GetString(bytes, 0, bytes.Length) != dateTimeValue) throw new Exception(); if (resize.Length == 3) - results = SaveResizedSubfile3(subFile, resize, bytes, fileHolder); + results = SaveResizedSubfile3(item, resize, returnAndDoNotWrite, bytes); else if (resize.Length == 5) - results = SaveResizedSubfile5(subFile, resize, bytes, fileHolder); + results = SaveResizedSubfile5(item, resize, returnAndDoNotWrite, bytes); else throw new Exception(); - if (fileHolder is not null && false) - { -#pragma warning disable CA1416 - using Image image = Image.FromFile(fileHolder.FullName); - if (image.PropertyIdList.Contains((int)IExif.Tags.DateTimeDigitized)) - { - string value; - DateTime checkDateTime; - PropertyItem? 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 && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime)) - _ = checkDateTime; - } - } -#pragma warning restore CA1416 - } return results; } - public byte[] GetResizedBytes(string outputResolution, string cResultsFullGroupDirectory, List> subFileTuples, Shared.Models.Item item, Shared.Models.Property property, Dictionary imageResizes) + public byte[] GetResizedBytes(string outputResolution, string cResultsFullGroupDirectory, List> subFileTuples, Shared.Models.Item item, Dictionary imageResizes) { byte[] results; - if (item.ImageFileHolder is null) - throw new NullReferenceException(nameof(item.ImageFileHolder)); if (!imageResizes.ContainsKey(outputResolution)) throw new Exception(); int[] resize = imageResizes[outputResolution]; int outputResolutionWidth = resize[_OutputResolutionWidthIndex]; int outputResolutionHeight = resize[_OutputResolutionHeightIndex]; int outputResolutionOrientation = resize[_OutputResolutionOrientationIndex]; - results = SaveResizedSubfile(item.ImageFileHolder.FullName, property, resize, fileHolder: null); + results = SaveResizedSubfile(item, resize, returnAndDoNotWrite: true); subFileTuples.Add(new Tuple(nameof(C_Resize), DateTime.Now)); return results; } @@ -343,19 +333,19 @@ public class C_Resize throw new NullReferenceException(nameof(item.ImageFileHolder)); if (item.ResizedFileHolder is null) throw new NullReferenceException(nameof(item.ResizedFileHolder)); - Shared.Models.FileHolder fileHolder = item.ResizedFileHolder; if (!imageResizes.ContainsKey(outputResolution)) throw new Exception(); - if (!fileHolder.Exists) + FileInfo fileInfo = new(item.ResizedFileHolder.FullName); + if (!fileInfo.Exists) { - FileInfo fileInfo = new(fileHolder.FullName); 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); - item.SetResizedFileHolder(_FilenameExtension, Shared.Models.Stateless.Methods.IFileHolder.Refresh(fileHolder)); + item.SetResizedFileHolder(_FilenameExtension, Shared.Models.Stateless.Methods.IFileHolder.Refresh(item.ResizedFileHolder)); + fileInfo.Refresh(); } } int[] resize = imageResizes[outputResolution]; @@ -365,9 +355,10 @@ public class C_Resize int[] originalCollection = imageResizes[original]; if (outputResolutionWidth == originalCollection[_OutputResolutionWidthIndex] && outputResolutionHeight == originalCollection[_OutputResolutionHeightIndex] && outputResolutionOrientation == originalCollection[_OutputResolutionOrientationIndex]) { - if (!fileHolder.Exists) + if (!fileInfo.Exists) { - File.Copy(item.ImageFileHolder.FullName, fileHolder.FullName); + File.Copy(item.ImageFileHolder.FullName, fileInfo.FullName); + item.SetResizedFileHolder(_FilenameExtension, Shared.Models.Stateless.Methods.IFileHolder.Refresh(item.ResizedFileHolder)); subFileTuples.Add(new Tuple(nameof(C_Resize), DateTime.Now)); } } @@ -378,13 +369,14 @@ public class C_Resize List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); if (_OverrideForResizeImages) check = true; - else if (!fileHolder.Exists) + else if (!fileInfo.Exists) check = true; - else if (dateTimes.Any() && dateTimes.Max() > fileHolder.LastWriteTime) + else if (dateTimes.Any() && dateTimes.Max() > fileInfo.LastWriteTime) check = true; if (check) { - _ = SaveResizedSubfile(item.ImageFileHolder.FullName, item.Property, resize, fileHolder); + _ = SaveResizedSubfile(item, resize, returnAndDoNotWrite: false); + item.SetResizedFileHolder(_FilenameExtension, Shared.Models.Stateless.Methods.IFileHolder.Refresh(item.ResizedFileHolder)); subFileTuples.Add(new Tuple(nameof(C_Resize), DateTime.Now)); } } @@ -551,6 +543,8 @@ public class C_Resize } } } + Shared.Models.FileHolder fileHolder = new(Path.Combine(AngleBracketCollection[0].Replace("<>", "()"), Path.GetFileName(item.ImageFileHolder.FullName))); + item.SetResizedFileHolder(_FilenameExtension, fileHolder); return results; } diff --git a/Shared/Models/FileHolder.cs b/Shared/Models/FileHolder.cs index 38fe9ae..8864fd3 100644 --- a/Shared/Models/FileHolder.cs +++ b/Shared/Models/FileHolder.cs @@ -5,26 +5,26 @@ namespace View_by_Distance.Shared.Models; public class FileHolder : Properties.IFileHolder { - protected readonly DateTime _CreationTime; + protected readonly DateTime? _CreationTime; protected readonly string? _DirectoryName; protected readonly bool _Exists; protected readonly string _ExtensionLowered; protected readonly string _FullName; - protected readonly DateTime _LastWriteTime; + protected readonly DateTime? _LastWriteTime; protected readonly long? _Length; protected readonly string _Name; protected readonly string _NameWithoutExtension; - public DateTime CreationTime => _CreationTime; + public DateTime? CreationTime => _CreationTime; public string? DirectoryName => _DirectoryName; public bool Exists => _Exists; public string ExtensionLowered => _ExtensionLowered; public string FullName => _FullName; - public DateTime LastWriteTime => _LastWriteTime; + public DateTime? LastWriteTime => _LastWriteTime; public long? Length => _Length; public string Name => _Name; public string NameWithoutExtension => _NameWithoutExtension; - public FileHolder(DateTime creationTime, string? directoryName, bool exists, string extensionLowered, string fullName, DateTime lastWriteTime, long? length, string name, string nameWithoutExtension) + public FileHolder(DateTime? creationTime, string? directoryName, bool exists, string extensionLowered, string fullName, DateTime? lastWriteTime, long? length, string name, string nameWithoutExtension) { _CreationTime = creationTime; _DirectoryName = directoryName; @@ -37,36 +37,26 @@ public class FileHolder : Properties.IFileHolder _NameWithoutExtension = nameWithoutExtension; } - public FileHolder(string fileName) + public FileHolder(FileInfo fileInfo) { - FileInfo fileInfo = new(fileName); - _CreationTime = fileInfo.CreationTime; - _CreationTime = fileInfo.CreationTime; + if (fileInfo.Exists) + { + _CreationTime = fileInfo.CreationTime; + _CreationTime = fileInfo.CreationTime; + _LastWriteTime = fileInfo.LastWriteTime; + _Length = fileInfo.Length; + } _DirectoryName = fileInfo.DirectoryName; _Exists = fileInfo.Exists; _ExtensionLowered = fileInfo.Extension.ToLower(); _FullName = fileInfo.FullName; - _LastWriteTime = fileInfo.LastWriteTime; - if (fileInfo.Exists) - _Length = fileInfo.Length; _Name = fileInfo.Name; _NameWithoutExtension = Path.GetFileNameWithoutExtension(fileInfo.FullName); } - public FileHolder(FileInfo fileInfo) - { - _CreationTime = fileInfo.CreationTime; - _CreationTime = fileInfo.CreationTime; - _DirectoryName = fileInfo.DirectoryName; - _Exists = fileInfo.Exists; - _ExtensionLowered = fileInfo.Extension.ToLower(); - _FullName = fileInfo.FullName; - _LastWriteTime = fileInfo.LastWriteTime; - if (fileInfo.Exists) - _Length = fileInfo.Length; - _Name = fileInfo.Name; - _NameWithoutExtension = Path.GetFileNameWithoutExtension(fileInfo.FullName); - } + public FileHolder(string fileName) : + this(new FileInfo(fileName)) + { } public override string ToString() { diff --git a/Shared/Models/Location.cs b/Shared/Models/Location.cs index ed42432..ace41cd 100644 --- a/Shared/Models/Location.cs +++ b/Shared/Models/Location.cs @@ -39,6 +39,24 @@ public class Location : Properties.ILocation, IEquatable this(bottom, confidence, left, GetNormalizedPixelPercentage(bottom, height, left, right, top, width, zCount), right, top) => Check(_Bottom, height, _Left, _NormalizedPixelPercentage, _Right, _Top, width, zCount); + public Location(double confidence, int factor, int height, Location location, int width, int zCount) + { + int x = (location.Right - location.Left) / factor; + int y = (location.Bottom - location.Top) / factor; + int bottom = Math.Min(location.Bottom + y, height); + int left = Math.Max(location.Left - x, 0); + int right = Math.Min(location.Right + x, width); + int top = Math.Max(location.Top - y, 0); + int normalizedPixelPercentage = GetNormalizedPixelPercentage(location.Bottom, height, location.Left, location.Right, location.Top, width, zCount); + Check(bottom, left, _NormalizedPixelPercentage, right, top, zCount); + _Confidence = confidence; + _Bottom = bottom; + _Left = left; + _NormalizedPixelPercentage = normalizedPixelPercentage; + _Right = right; + _Top = top; + } + public override bool Equals(object? obj) => Equals(obj as Location); public override string ToString() diff --git a/Shared/Models/Mapping.cs b/Shared/Models/Mapping.cs index 6abdeaf..5699397 100644 --- a/Shared/Models/Mapping.cs +++ b/Shared/Models/Mapping.cs @@ -46,4 +46,6 @@ public class Mapping : Properties.IMapping public void SetFiltered() => _Filtered = true; + public void SetFiltered(bool value) => _Filtered = value; + } \ No newline at end of file diff --git a/Shared/Models/Properties/IFileHolder.cs b/Shared/Models/Properties/IFileHolder.cs index f8f455f..20bbc5b 100644 --- a/Shared/Models/Properties/IFileHolder.cs +++ b/Shared/Models/Properties/IFileHolder.cs @@ -3,12 +3,12 @@ namespace View_by_Distance.Shared.Models.Properties; public interface IFileHolder { - public DateTime CreationTime { get; } + 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 DateTime? LastWriteTime { get; } public long? Length { get; } public string Name { get; } public string NameWithoutExtension { get; } diff --git a/Shared/Models/SaveContainer.cs b/Shared/Models/SaveContainer.cs new file mode 100644 index 0000000..41c7c98 --- /dev/null +++ b/Shared/Models/SaveContainer.cs @@ -0,0 +1,53 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace View_by_Distance.Shared.Models; + +public class SaveContainer +{ + + protected readonly string _CheckFile; + protected readonly string _Directory; + protected readonly FileHolder? _FaceFileHolder; + protected readonly FileHolder? _HiddenFaceFileHolder; + protected readonly string _Json; + protected readonly FileHolder? _FacePartsFileHolder; + protected readonly FileHolder? _ResizedFileHolder; + protected readonly string _ShortcutFile; + public string CheckFile => _CheckFile; + public string Directory => _Directory; + public FileHolder? FaceFileHolder => _FaceFileHolder; + public FileHolder? HiddenFaceFileHolder => _HiddenFaceFileHolder; + public string Json => _Json; + public FileHolder? FacePartsFileHolder => _FacePartsFileHolder; + public FileHolder? ResizedFileHolder => _ResizedFileHolder; + public string ShortcutFile => _ShortcutFile; + + [JsonConstructor] + public SaveContainer(string checkFile, string directory, FileHolder? faceFileHolder, FileHolder? hiddenFaceFileHolder, string json, FileHolder? facePartsFileHolder, FileHolder? resizedFileHolder, string shortcutFile) + { + _CheckFile = checkFile; + _Directory = directory; + _FaceFileHolder = faceFileHolder; + _HiddenFaceFileHolder = hiddenFaceFileHolder; + _Json = json; + _FacePartsFileHolder = facePartsFileHolder; + _ResizedFileHolder = resizedFileHolder; + _ShortcutFile = shortcutFile; + } + + public SaveContainer(string directory) : + this(string.Empty, directory, null, null, string.Empty, null, null, string.Empty) + { } + + public SaveContainer(string checkFile, string directory, string json) : + this(checkFile, directory, null, null, json, null, null, string.Empty) + { } + + 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/Stateless/IFaceDistance.cs b/Shared/Models/Stateless/IFaceDistance.cs index e47a66c..15cac2f 100644 --- a/Shared/Models/Stateless/IFaceDistance.cs +++ b/Shared/Models/Stateless/IFaceDistance.cs @@ -5,6 +5,7 @@ public interface IFaceDistance // 637972153144596958 // const int MaximumPer = 999; + const int HiddenImageFactor = 2; const int MaximumPer = 9999; const double Tolerance = 0.6d; diff --git a/Shared/Models/Stateless/IPersonBirthday.cs b/Shared/Models/Stateless/IPersonBirthday.cs index d3a376b..4a6da5a 100644 --- a/Shared/Models/Stateless/IPersonBirthday.cs +++ b/Shared/Models/Stateless/IPersonBirthday.cs @@ -3,6 +3,7 @@ public interface IPersonBirthday { + const int FirstYear = 1500; const string Format = "yyyy-MM-dd_HH"; } \ No newline at end of file diff --git a/Shared/Models/Stateless/Methods/ILocation.cs b/Shared/Models/Stateless/Methods/ILocation.cs index f6fc9f5..1ffca1a 100644 --- a/Shared/Models/Stateless/Methods/ILocation.cs +++ b/Shared/Models/Stateless/Methods/ILocation.cs @@ -7,6 +7,10 @@ public interface ILocation static Models.Location? GetLocation(Models.Location? location, int height, int width, int zCount) => location is null ? null : new(location.Confidence, height, location, width, zCount); + Models.Location? TestStatic_GetLocation(int factor, Models.Location? location, int height, int width, int zCount); + static Models.Location? GetLocation(int factor, Models.Location? location, int height, int width, int zCount) => + location is null ? null : new(location.Confidence, factor, 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(); diff --git a/Shared/Models/Stateless/Methods/IPath.cs b/Shared/Models/Stateless/Methods/IPath.cs index de90936..49a7f8d 100644 --- a/Shared/Models/Stateless/Methods/IPath.cs +++ b/Shared/Models/Stateless/Methods/IPath.cs @@ -5,7 +5,7 @@ public interface IPath string TestStatic_GetRelativePath(string path, int length); static string GetRelativePath(string path, int length) - => XPath.GetRelativePath(path, length); + => XPath.GetRelativePath(path, length, forceExtensionToLower: false); bool TestStatic_DeleteEmptyDirectories(string rootDirectory); static bool DeleteEmptyDirectories(string rootDirectory) @@ -15,6 +15,10 @@ public interface IPath static List GetDirectoryNames(string directory) => XPath.GetDirectoryNames(directory); + string TestStatic_GetRelativePath(string path, int length, bool forceExtensionToLower); + static string GetRelativePath(string path, int length, bool forceExtensionToLower) + => XPath.GetRelativePath(path, length, forceExtensionToLower); + 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); diff --git a/Shared/Models/Stateless/Methods/Person.cs b/Shared/Models/Stateless/Methods/Person.cs index c402618..99b6ca8 100644 --- a/Shared/Models/Stateless/Methods/Person.cs +++ b/Shared/Models/Stateless/Methods/Person.cs @@ -66,7 +66,7 @@ internal abstract class Person Dictionary results = new(); string[] segments; DateTime personKey; - DateTime incrementDate = new(1500, 1, 1); + DateTime incrementDate = new(Stateless.IPersonBirthday.FirstYear, 1, 1); string[] lines = File.ReadAllLines(knownPeopleFile); _ = incrementDate.AddDays(lines.Length); System.Globalization.CultureInfo cultureInfo = System.Globalization.CultureInfo.InvariantCulture; @@ -83,12 +83,15 @@ internal abstract class Person continue; results.Add(personKey, segments); } - int countBefore = results.Count; - DateTime minimumDateTime = results.Keys.Min(); - for (int i = 1; i < (1000 - countBefore); i++) + if (results.Any()) { - personKey = minimumDateTime.AddDays(i * -1); - results.Add(personKey, new string[] { personKey.ToString(Stateless.IPerson.KeyFormat) }); + int countBefore = results.Count; + DateTime minimumDateTime = results.Keys.Min(); + for (int i = 1; i < (1000 - countBefore); i++) + { + personKey = minimumDateTime.AddDays(i * -1); + results.Add(personKey, new string[] { personKey.ToString(Stateless.IPerson.KeyFormat) }); + } } return results.OrderBy(l => l.Key).ToDictionary(l => l.Key, l => l.Value); } @@ -202,23 +205,21 @@ internal abstract class Person Models.Person? person; string localKnownPeopleFile; DateTime dateTime = DateTime.MinValue; - string directory = Path.Combine(storage.PeopleRootDirectory, "{}"); - if (!Directory.Exists(directory)) - _ = Directory.CreateDirectory(directory); - string? rootDirectoryParent = Path.GetDirectoryName(storage.RootDirectory); - if (string.IsNullOrEmpty(rootDirectoryParent)) - throw new NullReferenceException(nameof(rootDirectoryParent)); - if (!Directory.Exists(rootDirectoryParent)) + string peopleContentDirectory = Path.Combine(storage.PeopleRootDirectory, "()"); + string peopleSingletonDirectory = Path.Combine(storage.PeopleRootDirectory, "{}"); + if (!Directory.Exists(peopleSingletonDirectory)) + _ = Directory.CreateDirectory(peopleSingletonDirectory); + if (!Directory.Exists(peopleContentDirectory)) localKnownPeopleFile = string.Empty; else { - files = Directory.GetFiles(rootDirectoryParent, "*People*.txt", SearchOption.TopDirectoryOnly); + files = Directory.GetFiles(peopleContentDirectory, "*People*.txt", SearchOption.TopDirectoryOnly); if (files.Any()) localKnownPeopleFile = files[0]; else localKnownPeopleFile = string.Empty; } - files = Directory.GetFiles(directory, "*.json", SearchOption.TopDirectoryOnly); + files = Directory.GetFiles(peopleSingletonDirectory, "*.json", SearchOption.TopDirectoryOnly); if (!files.Any() && string.IsNullOrEmpty(localKnownPeopleFile)) throw new Exception("Copy \"KnownPeople.txt\" file from server!"); foreach (string file in files) diff --git a/Shared/Models/Stateless/Methods/XPath.cs b/Shared/Models/Stateless/Methods/XPath.cs index 594be2c..0c6c6be 100644 --- a/Shared/Models/Stateless/Methods/XPath.cs +++ b/Shared/Models/Stateless/Methods/XPath.cs @@ -3,9 +3,25 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods; internal abstract class XPath { - internal static string GetRelativePath(string path, int length) + internal static string GetRelativePath(string path, int length, bool forceExtensionToLower) { - string result = path[length..].Replace(@"\", "/"); + string result; + if (forceExtensionToLower) + { + string extension = Path.GetExtension(path); + string extensionLowered = Path.GetExtension(path).ToLower(); + if (extension != extensionLowered) + { + string? directoryName = Path.GetDirectoryName(path); + if (string.IsNullOrEmpty(directoryName)) + throw new NullReferenceException(directoryName); + string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path); + if (string.IsNullOrEmpty(fileNameWithoutExtension)) + throw new NullReferenceException(fileNameWithoutExtension); + path = Path.Combine(directoryName, $"{fileNameWithoutExtension}{extensionLowered}"); + } + } + result = path[length..].Replace(@"\", "/"); return result; } diff --git a/Tests/UnitTestResize.cs b/Tests/UnitTestResize.cs index a45a62a..1ded7fb 100644 --- a/Tests/UnitTestResize.cs +++ b/Tests/UnitTestResize.cs @@ -172,8 +172,10 @@ public class UnitTestResize { // string sourceFileName = "IMG_0067.jpg"; // string sourceDirectoryName = "Mackenzie Prom 2017"; - string sourceFileName = "Fall 2005 (113).jpg"; - string sourceDirectoryName = "=2005.3 Fall"; + // string sourceFileName = "Fall 2005 (113).jpg"; + // string sourceDirectoryName = "=2005.3 Fall"; + string sourceFileName = "12314542_10208270578946392_3555034423896018896_o.jpg"; + string sourceDirectoryName = "Other"; Item item; Model? model = null; bool reverse = false; @@ -242,10 +244,8 @@ public class UnitTestResize } (int _, metadataCollection) = metadata.GetMetadataCollection(bResultsFullGroupDirectory, subFileTuples, parseExceptions, item); imageResizeKeyValuePairs = resize.GetResizeKeyValuePairs(cResultsFullGroupDirectory, subFileTuples, parseExceptions, original, metadataCollection, item); - FileHolder resizedFileHolder = new(Path.Combine(resize.AngleBracketCollection[0].Replace("<>", "()"), Path.GetFileName(item.ImageFileHolder.FullName))); - item.SetResizedFileHolder(resize.FilenameExtension, resizedFileHolder); + Assert.IsNotNull(item.ResizedFileHolder); resize.SaveResizedSubfile(outputResolution, cResultsFullGroupDirectory, subFileTuples, item, original, imageResizeKeyValuePairs); - item.SetResizedFileHolder(resize.FilenameExtension, IFileHolder.Refresh(resizedFileHolder)); } } \ No newline at end of file diff --git a/TestsWithFaceRecognitionDotNet/UnitTestFace.cs b/TestsWithFaceRecognitionDotNet/UnitTestFace.cs index 0fb5375..0d16b6b 100644 --- a/TestsWithFaceRecognitionDotNet/UnitTestFace.cs +++ b/TestsWithFaceRecognitionDotNet/UnitTestFace.cs @@ -206,11 +206,8 @@ public class UnitTestFace } (int _, metadataCollection) = metadata.GetMetadataCollection(bResultsFullGroupDirectory, subFileTuples, parseExceptions, item); imageResizeKeyValuePairs = resize.GetResizeKeyValuePairs(cResultsFullGroupDirectory, subFileTuples, parseExceptions, original, metadataCollection, item); - 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(resize.FilenameExtension, IFileHolder.Refresh(resizedFileHolder)); Assert.IsNotNull(item.ResizedFileHolder); + resize.SaveResizedSubfile(outputResolution, cResultsFullGroupDirectory, subFileTuples, item, original, imageResizeKeyValuePairs); Image image = FaceRecognition.LoadImageFile(item.ResizedFileHolder.FullName); Assert.IsNotNull(image); FaceRecognition faceRecognition = new(_Configuration.NumberOfTimesToUpsample, _Configuration.NumberOfJitters, predictorModel, model, modelParameter);