using System.Drawing; using System.Text.Json; using View_by_Distance.Metadata.Models; using View_by_Distance.Property.Models; using View_by_Distance.Resize.Models; using View_by_Distance.Shared.Models.Stateless; namespace View_by_Distance.Instance.Models; /// // *.png /// internal class D2_FaceLandmarks { internal List AngleBracketCollection { get; } private readonly Serilog.ILogger? _Log; private readonly Configuration _Configuration; internal D2_FaceLandmarks(Configuration configuration) { _Configuration = configuration; AngleBracketCollection = new List(); _Log = Serilog.Log.ForContext(); } public override string ToString() { string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true }); return result; } #pragma warning disable CA1416 private static Bitmap RotateBitmap(Image image, float angle) { Bitmap result; Bitmap bitmap = new(image); result = D_Face.RotateBitmap(bitmap, angle); if (bitmap is not null) bitmap.Dispose(); return result; } private static void SaveFaceLandmarkImages(List faceCollections, List imageFiles, int pointSize, FileHolder resizedFileHolder) { int x; int y; D_Face face; int width; int height; string imageFileFullName; Bitmap rotated; string rotatedImageFileFullName; Shared.Models.FacePoint[] facePoints; for (int i = 0; i < faceCollections.Count; i++) { if (!faceCollections[i].Populated) continue; face = faceCollections[i]; imageFileFullName = imageFiles[i][0]; rotatedImageFileFullName = imageFiles[i][1]; try { using (Image image = Image.FromFile(resizedFileHolder.FullName)) { using Graphics graphic = Graphics.FromImage(image); if (face.FaceLandmarks is null || !face.FaceLandmarks.Any()) { width = face.Location.Right - face.Location.Left; height = face.Location.Bottom - face.Location.Top; graphic.DrawEllipse(Pens.Red, face.Location.Left, face.Location.Top, width, height); } else { foreach (KeyValuePair keyValuePair in face.FaceLandmarks) { facePoints = keyValuePair.Value.ToArray(); foreach (Shared.Models.FacePoint facePoint in facePoints) graphic.DrawEllipse(Pens.GreenYellow, face.Location.Left + facePoint.X - pointSize, face.Location.Top + facePoint.Y - pointSize, pointSize * 2, pointSize * 2); if (keyValuePair.Key == FacePart.Chin.ToString()) continue; if (facePoints.Length < 3) continue; x = (int)(from l in facePoints select l.X).Average(); y = (int)(from l in facePoints select l.Y).Average(); graphic.DrawEllipse(Pens.Purple, face.Location.Left + x - pointSize, face.Location.Top + y - pointSize, pointSize * 2, pointSize * 2); } } image.Save(imageFileFullName, System.Drawing.Imaging.ImageFormat.Png); } if (face.α.HasValue) { using Image image = Image.FromFile(resizedFileHolder.FullName); rotated = RotateBitmap(image, (float)face.α.Value); if (rotated is not null) { rotated.Save(rotatedImageFileFullName, System.Drawing.Imaging.ImageFormat.Png); rotated.Dispose(); } } } catch (Exception) { } } } #pragma warning restore CA1416 internal void SaveFaceLandmarkImages(List> subFileTuples, List parseExceptions, Item item, List faceCollections) { if (item.ImageFileHolder is null) throw new NullReferenceException(nameof(item.ImageFileHolder)); if (item.ResizedFileHolder is null) throw new NullReferenceException(nameof(item.ResizedFileHolder)); FileInfo fileInfo; bool check = false; string parentCheck; const int pointSize = 2; FileInfo rotatedFileInfo; DateTime? dateTime = null; long ticks = DateTime.Now.Ticks; List imageFiles = new(); bool updateDateWhenMatches = false; string facesDirectory = Path.Combine(AngleBracketCollection[0].Replace("<>", "()"), item.ImageFileHolder.NameWithoutExtension); string[] changesFrom = new string[] { nameof(A_Property), nameof(B_Metadata), nameof(C_Resize), nameof(D_Face) }; List dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList(); if (!Directory.Exists(facesDirectory)) _ = Directory.CreateDirectory(facesDirectory); for (int i = 0; i < faceCollections.Count; i++) { if (!faceCollections[i].Populated) { imageFiles.Add(Array.Empty()); continue; } fileInfo = new FileInfo(Path.Combine(facesDirectory, $"{i} - {item.ImageFileHolder.NameWithoutExtension}.png")); if (!fileInfo.Exists) { if (fileInfo.Directory?.Parent is null) throw new Exception(); parentCheck = Path.Combine(fileInfo.Directory.Parent.FullName, fileInfo.Name); if (File.Exists(parentCheck)) File.Delete(parentCheck); } if (string.IsNullOrEmpty(fileInfo.DirectoryName)) continue; rotatedFileInfo = new FileInfo(Path.Combine(fileInfo.DirectoryName, string.Concat(Path.GetFileNameWithoutExtension(fileInfo.FullName), " - ", i, " - R", Path.GetExtension(fileInfo.FullName)))); imageFiles.Add(new string[] { fileInfo.FullName, rotatedFileInfo.FullName }); if (check) continue; if (_Configuration.OverrideForFaceLandmarkImages is null) check = false; else if (_Configuration.OverrideForFaceLandmarkImages.Value) check = true; else if (!fileInfo.Exists) check = true; else if (!rotatedFileInfo.Exists) check = true; else if (dateTimes.Any() && dateTimes.Max() > fileInfo.LastWriteTime) check = true; if (check && !updateDateWhenMatches) { updateDateWhenMatches = dateTimes.Any() && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime; dateTime = !updateDateWhenMatches ? null : dateTimes.Max(); } } if (check) SaveFaceLandmarkImages(faceCollections, imageFiles, pointSize, item.ResizedFileHolder); } }