Mike Phares 130e3b6528 Mostly Sorting
Video Merge as 4, 5, and 6
2025-03-22 16:50:47 -07:00

527 lines
27 KiB
C#

using System.Collections.ObjectModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
using View_by_Distance.FaceRecognitionDotNet;
using View_by_Distance.Metadata.Models;
using View_by_Distance.Metadata.Models.Stateless.Methods;
using View_by_Distance.Property.Models;
using View_by_Distance.Resize.Models;
using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Properties;
using View_by_Distance.Shared.Models.Stateless;
using View_by_Distance.Shared.Models.Stateless.Methods;
namespace View_by_Distance.Face.Models;
/// <summary>
// List<D_Faces>
/// </summary>
public class D_Face : IFaceD
{
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 bool _OverrideForFaceImages;
private readonly bool _LoadPhotoPrismLocations;
private readonly ImageCodecInfo _ImageCodecInfo;
private readonly ModelParameter _ModelParameter;
private readonly PredictorModel _PredictorModel;
private readonly bool _CheckDFaceAndUpWriteDates;
private readonly bool _PropertiesChangedForFaces;
private readonly ConstructorInfo _ConstructorInfo;
private readonly float _RectangleIntersectMinimum;
private readonly int _FaceDistanceHiddenImageFactor;
private readonly EncoderParameters _EncoderParameters;
private readonly ImageCodecInfo _HiddenImageCodecInfo;
private readonly bool _ForceFaceLastWriteTimeToCreationTime;
private readonly EncoderParameters _HiddenEncoderParameters;
private readonly IPropertyConfiguration _PropertyConfiguration;
private readonly JsonSerializerOptions _WriteIndentedAndWhenWritingNull;
private readonly ReadOnlyDictionary<byte, ReadOnlyCollection<string>>[] _ResultContentFileGroups;
private readonly ReadOnlyDictionary<byte, ReadOnlyCollection<string>>[] _ResultCollectionFileGroups;
public D_Face(
string argZero,
IPropertyConfiguration propertyConfiguration,
bool checkDFaceAndUpWriteDates,
EncoderParameters encoderParameters,
int faceDistanceHiddenImageFactor,
string filenameExtension,
bool forceFaceLastWriteTimeToCreationTime,
EncoderParameters hiddenEncoderParameters,
string hiddenFileNameExtension,
ImageCodecInfo hiddenImageCodecInfo,
ImageCodecInfo imageCodecInfo,
bool loadPhotoPrismLocations,
string modelDirectory,
string modelName,
bool overrideForFaceImages,
string predictorModelName,
bool propertiesChangedForFaces,
float[] rectangleIntersectMinimums)
{
_ArgZero = argZero;
_ImageCodecInfo = imageCodecInfo;
_EncoderParameters = encoderParameters;
_FileNameExtension = filenameExtension;
_HiddenImageCodecInfo = hiddenImageCodecInfo;
_OverrideForFaceImages = overrideForFaceImages;
_PropertyConfiguration = propertyConfiguration;
_HiddenEncoderParameters = hiddenEncoderParameters;
_HiddenFileNameExtension = hiddenFileNameExtension;
_LoadPhotoPrismLocations = loadPhotoPrismLocations;
_CheckDFaceAndUpWriteDates = checkDFaceAndUpWriteDates;
_PropertiesChangedForFaces = propertiesChangedForFaces;
_RectangleIntersectMinimum = rectangleIntersectMinimums.Min();
_FaceDistanceHiddenImageFactor = faceDistanceHiddenImageFactor;
_ForceFaceLastWriteTimeToCreationTime = forceFaceLastWriteTimeToCreationTime;
_ResultContentFileGroups = [new(new Dictionary<byte, ReadOnlyCollection<string>>())];
_ResultCollectionFileGroups = [new(new Dictionary<byte, ReadOnlyCollection<string>>())];
(Model model, PredictorModel predictorModel, ModelParameter modelParameter) = GetModel(modelDirectory, modelName, predictorModelName);
_Model = model;
_PredictorModel = predictorModel;
_ModelParameter = modelParameter;
ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, [], null) ?? throw new Exception();
_ConstructorInfo = constructorInfo;
_WriteIndentedAndWhenWritingNull = new JsonSerializerOptions { WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull };
}
void IFaceD.ReSaveFace(ExifDirectory exifDirectory, FilePath filePath, Shared.Models.Face face, bool mappedFile)
{
FileInfo fileInfo = new(filePath.FullName);
if (fileInfo.Exists)
{
string? json;
short type = 2;
string? model;
string? maker;
string checkFile = $"{filePath.FullName}.exif";
const int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist;
// const int author = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagWinAuthor; // 40093
if (mappedFile)
{
json = IMetadata.GetOutputResolution(exifDirectory);
if (json is not null && json.Contains(nameof(DateTime)))
return;
(maker, model) = Get(json);
}
else
{
maker = IMetadata.GetMaker(exifDirectory);
model = IMetadata.GetModel(exifDirectory);
ExifDirectory? faceExifDirectory = IMetadata.GetExifDirectory(filePath);
json = IMetadata.GetOutputResolution(faceExifDirectory);
if (json is not null && json.Contains(nameof(DateTime)))
return;
}
MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
FaceFile faceFile = new(face.Mapping?.MappingFromLocation?.AreaPermyriad,
face.Mapping?.MappingFromLocation?.ConfidencePercent,
geoLocation?.ToDmsString(),
face.DateTime,
null,
face.FaceParts,
face.Location,
maker,
null,
model,
face.OutputResolution);
string faceFileJson = JsonSerializer.Serialize(faceFile, FaceFileGenerationContext.Default.FaceFile);
ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, [], null) ?? throw new Exception();
PropertyItem? propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(constructorInfo, artist, type, faceFileJson);
#pragma warning disable CA1416
Bitmap bitmap = new(fileInfo.FullName);
bitmap.SetPropertyItem(propertyItem);
bitmap.Save(checkFile);
bitmap.Dispose();
#pragma warning restore CA1416
File.SetLastWriteTime(checkFile, fileInfo.LastWriteTime);
File.Delete(fileInfo.FullName);
File.Move(checkFile, fileInfo.FullName);
}
}
private static (string?, string?) Get(string? json)
{
string? model;
string? maker;
FaceFile? faceFile = json is null ? null : JsonSerializer.Deserialize(json, FaceFileGenerationContext.Default.FaceFile);
if (faceFile is null || faceFile.Location is null)
(maker, model) = (null, null);
else
(maker, model) = (faceFile.Maker, faceFile.Model);
return (maker, model);
}
public override string ToString()
{
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
return result;
}
public void Update(string dResultsFullGroupDirectory)
{
ReadOnlyDictionary<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePairs = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(_PropertyConfiguration, dResultsFullGroupDirectory, [_PropertyConfiguration.ResultCollection, _PropertyConfiguration.ResultContent]);
foreach (KeyValuePair<string, ReadOnlyDictionary<byte, ReadOnlyCollection<string>>> keyValuePair in keyValuePairs)
{
if (keyValuePair.Key == _PropertyConfiguration.ResultContent)
_ResultContentFileGroups[0] = keyValuePair.Value;
else if (keyValuePair.Key == _PropertyConfiguration.ResultCollection)
_ResultCollectionFileGroups[0] = keyValuePair.Value;
else
throw new Exception();
}
}
public List<(Shared.Models.Face, FileHolder?, string, bool)> SaveFaces(FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, MappingFromItem mappingFromItem, ExifDirectory exifDirectory, List<Shared.Models.Face> faces)
{
List<(Shared.Models.Face, FileHolder?, string, bool Save)> results = [];
bool save;
FileInfo fileInfo;
FileHolder fileHolder;
string deterministicHashCodeKey;
string fileName = mappingFromItem.FilePath.NameWithoutExtension;
string[] changesFrom = [nameof(A_Property), nameof(B_Metadata), nameof(C_Resize)];
List<DateTime> dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList();
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath);
string directory = _ResultContentFileGroups[0][cei.Enum][cei.Index];
DirectoryInfo directoryInfo = new(Path.Combine(directory, fileName));
MoveIf(fileName, cei, directory, directoryInfo);
foreach (Shared.Models.Face face in faces)
{
save = false;
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null)
{
results.Add(new(face, null, string.Empty, save));
continue;
}
deterministicHashCodeKey = Shared.Models.Stateless.Methods.IMapping.GetDeterministicHashCodeKey(filePath, face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution);
fileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_FileNameExtension}"));
fileHolder = FileHolder.Get(fileInfo);
if (!directoryInfo.Exists)
save = true;
else if (_OverrideForFaceImages)
save = true;
else if (!fileHolder.Exists)
save = true;
else if (_CheckDFaceAndUpWriteDates && dateTimes.Count > 0 && dateTimes.Max() > fileInfo.LastWriteTime)
save = true;
results.Add(new(face, fileHolder, Path.Combine(directoryInfo.FullName, $"{deterministicHashCodeKey}{mappingFromItem.FilePath.ExtensionLowered}{_HiddenFileNameExtension}"), save));
}
if (results.Any(l => l.Save))
{
if (!directoryInfo.Exists)
_ = Directory.CreateDirectory(directoryInfo.FullName);
SaveFaces(mappingFromItem.ResizedFileHolder, exifDirectory, results);
}
return results;
}
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, FileInfo fileInfo)
{
string[] segments = directory.Split(cei.Combined);
string? checkDirectory = segments.Length == 1 ?
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
segments.Length == 2 ?
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
null;
if (checkDirectory is not null && Directory.Exists(checkDirectory))
{
string checkFile = Path.Combine(checkDirectory, fileName);
if (File.Exists(checkFile))
{
File.Move(checkFile, fileInfo.FullName);
fileInfo.Refresh();
}
}
}
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, DirectoryInfo directoryInfo)
{
string[] segments = directory.Split(cei.Combined);
string? checkDirectory = segments.Length == 1 ?
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
segments.Length == 2 ?
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
null;
if (checkDirectory is not null && Directory.Exists(checkDirectory))
{
string checkFile = Path.Combine(checkDirectory, fileName);
if (Directory.Exists(checkFile))
{
Directory.Move(checkFile, directoryInfo.FullName);
directoryInfo.Refresh();
}
}
}
public List<Shared.Models.Face> GetFaces(string outputResolution, string cResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection)
{
List<Shared.Models.Face>? results;
string? json;
List<Location> locations;
string[] changesFrom = [nameof(A_Property), nameof(B_Metadata), nameof(C_Resize)];
List<DateTime> dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList();
string fileName = $"{mappingFromItem.FilePath.NameWithoutExtension}{mappingFromItem.FilePath.ExtensionLowered}.json";
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, filePath);
string directory = _ResultCollectionFileGroups[0][cei.Enum][cei.Index];
FileInfo fileInfo = new(Path.Combine(directory, fileName));
MoveIf(fileName, cei, directory, fileInfo);
if (_ForceFaceLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete")))
{
File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName);
fileInfo.Refresh();
}
if (_ForceFaceLastWriteTimeToCreationTime && fileInfo.Exists && fileInfo.LastWriteTime != fileInfo.CreationTime)
{
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
fileInfo.Refresh();
}
if (_PropertiesChangedForFaces)
results = null;
else if (!fileInfo.Exists)
results = null;
else if (_CheckDFaceAndUpWriteDates && dateTimes.Count > 0 && dateTimes.Max() > fileInfo.LastWriteTime)
results = null;
else
{
json = Shared.Models.Stateless.Methods.IFace.GetJson(fileInfo.FullName);
try
{
results = JsonSerializer.Deserialize<List<Shared.Models.Face>>(json);
if (results is null)
throw new NullReferenceException(nameof(results));
subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), fileInfo.LastWriteTime));
}
catch (Exception)
{
results = null;
parseExceptions.Add(nameof(D_Face));
}
}
if (!_LoadPhotoPrismLocations || mappingFromPhotoPrismCollection is null || results is null)
locations = [];
else
locations = Shared.Models.Stateless.Methods.ILocation.GetLocations(results, mappingFromPhotoPrismCollection, _RectangleIntersectMinimum);
if (results is null || locations.Count > 0)
{
results = GetFaces(outputResolution, cResultsFullGroupDirectory, property, mappingFromItem, outputResolutionToResize, locations);
if (results.Count == 0)
File.Move(mappingFromItem.ResizedFileHolder.FullName, $"{mappingFromItem.ResizedFileHolder.FullName}.err");
else
{
bool updateDateWhenMatches = dateTimes.Count > 0 && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime;
DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max();
json = JsonSerializer.Serialize(results, _WriteIndentedAndWhenWritingNull);
if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime))
{
if (!_ForceFaceLastWriteTimeToCreationTime)
subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), DateTime.Now));
else
{
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
fileInfo.Refresh();
subFileTuples.Add(new Tuple<string, DateTime>(nameof(D_Face), fileInfo.CreationTime));
}
}
}
}
return results;
}
private List<Shared.Models.Face> GetFaces(string outputResolution, string cResultsFullGroupDirectory, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, List<Location> locations)
{
if (_PropertyConfiguration.NumberOfJitters is null)
throw new NullReferenceException(nameof(_PropertyConfiguration.NumberOfJitters));
if (_PropertyConfiguration.NumberOfTimesToUpsample is null)
throw new NullReferenceException(nameof(_PropertyConfiguration.NumberOfTimesToUpsample));
List<Shared.Models.Face> results = [];
FaceRecognitionDotNet.Image? unknownImage;
try
{
if (mappingFromItem.ResizedFileHolder.ExtensionLowered != ".tif")
unknownImage = FaceRecognition.LoadImageFile(mappingFromItem.ResizedFileHolder.FullName);
else
{
int outputQuality = 100;
string extension = ".png";
string file = Path.Combine(cResultsFullGroupDirectory, $"{mappingFromItem.ResizedFileHolder.Name}{extension}");
(ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) = C_Resize.GetTuple(extension, outputQuality);
#pragma warning disable CA1416
System.Drawing.Image image = System.Drawing.Image.FromFile(mappingFromItem.ResizedFileHolder.FullName);
image.Save(Path.Combine(cResultsFullGroupDirectory, $"{mappingFromItem.ResizedFileHolder.Name}{filenameExtension}"), imageCodecInfo, encoderParameters);
image.Dispose();
#pragma warning restore CA1416
unknownImage = FaceRecognition.LoadImageFile(file);
File.Delete(file);
}
}
catch (Exception)
{ unknownImage = null; }
if (unknownImage is not null)
{
(int outputResolutionWidth, int outputResolutionHeight, int outputResolutionOrientation) = Resize.Models.Stateless.Methods.IResize.Get(outputResolution, outputResolutionToResize);
List<(Location Location, FaceRecognitionDotNet.FaceEncoding? FaceEncoding, Dictionary<FacePart, FacePoint[]>? FaceParts)> collection;
FaceRecognition faceRecognition = new(_PropertyConfiguration.NumberOfJitters.Value, _PropertyConfiguration.NumberOfTimesToUpsample.Value, _Model, _ModelParameter, _PredictorModel);
collection = faceRecognition.GetCollection(unknownImage, locations, includeFaceEncoding: true, includeFaceParts: true);
if (collection.Count == 0)
results.Add(new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, location: null));
else
{
double[] rawEncoding;
Shared.Models.Face face;
Shared.Models.FaceEncoding convertedFaceEncoding;
foreach ((Location location, FaceRecognitionDotNet.FaceEncoding? faceEncoding, Dictionary<FacePart, FacePoint[]>? faceParts) in collection)
{
face = new(property, outputResolutionWidth, outputResolutionHeight, outputResolutionOrientation, location);
if (faceEncoding is not null)
{
rawEncoding = faceEncoding.GetRawEncoding();
convertedFaceEncoding = new(rawEncoding, faceEncoding.Size);
face.SetFaceEncoding(convertedFaceEncoding);
}
if (faceParts is not null)
face.SetFaceParts(faceParts);
results.Add(face);
}
}
unknownImage.Dispose();
faceRecognition.Dispose();
}
return results;
}
private static (Model model, PredictorModel predictorModel, ModelParameter modelParameter) GetModel(string modelDirectory, string modelName, string predictorModelName)
{
(Model, PredictorModel, ModelParameter) result;
Array array;
Model? model = null;
array = Enum.GetValues<Model>();
PredictorModel? predictorModel = null;
foreach (Model check in array)
{
if (modelName.Contains(check.ToString()))
{
model = check;
break;
}
}
if (model is null)
throw new Exception("Destination directory must have Model name!");
model = model.Value;
array = Enum.GetValues<PredictorModel>();
foreach (PredictorModel check in array)
{
if (predictorModelName.Contains(check.ToString()))
{
predictorModel = check;
break;
}
}
if (predictorModel is null)
throw new Exception("Destination directory must have Predictor Model name!");
predictorModel = predictorModel.Value;
ModelParameter modelParameter = new()
{
CnnFaceDetectorModel = File.ReadAllBytes(Path.Combine(modelDirectory, "mmod_human_face_detector.dat")),
FaceRecognitionModel = File.ReadAllBytes(Path.Combine(modelDirectory, "dlib_face_recognition_resnet_model_v1.dat")),
PosePredictor5FaceLandmarksModel = File.ReadAllBytes(Path.Combine(modelDirectory, "shape_predictor_5_face_landmarks.dat")),
PosePredictor68FaceLandmarksModel = File.ReadAllBytes(Path.Combine(modelDirectory, "shape_predictor_68_face_landmarks.dat"))
};
result = new(model.Value, predictorModel.Value, modelParameter);
return result;
}
private void SaveFaces(FileHolder resizedFileHolder, ExifDirectory exifDirectory, List<(Shared.Models.Face, FileHolder?, string, bool)> collection)
{
int width;
int height;
Bitmap bitmap;
short type = 2;
FaceFile faceFile;
Graphics graphics;
Location? location;
Rectangle rectangle;
string faceFileJson;
string faceEncodingJson;
PropertyItem? propertyItem;
string? maker = IMetadata.GetMaker(exifDirectory);
string? model = IMetadata.GetModel(exifDirectory);
#pragma warning disable CA1416
using Bitmap source = new(resizedFileHolder.FullName);
MetadataExtractor.GeoLocation? geoLocation = IMetadata.GeoLocation(exifDirectory);
const int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist; // 315
const int userComment = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagUserComment;
foreach ((Shared.Models.Face face, FileHolder? fileHolder, string fileName, bool save) in collection)
{
if (!save)
continue;
if (fileHolder is null)
continue;
if (face.FaceEncoding is null || face?.Location is null || face?.OutputResolution is null)
continue;
if (_OverrideForFaceImages && fileHolder.Exists)
{
IFaceD dFace = this;
FilePath filePath = FilePath.Get(_PropertyConfiguration, fileHolder, index: null);
dFace.ReSaveFace(exifDirectory, filePath, face, mappedFile: false);
continue;
}
location = Shared.Models.Stateless.Methods.ILocation.GetLocation(face.Location, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, source.Height, source.Width, collection.Count);
if (location is null)
continue;
width = location.Right - location.Left;
height = location.Bottom - location.Top;
faceEncodingJson = JsonSerializer.Serialize(face.FaceEncoding);
rectangle = new Rectangle(location.Left, location.Top, width, height);
faceFile = new(face.Mapping?.MappingFromLocation?.AreaPermyriad,
face.Mapping?.MappingFromLocation?.ConfidencePercent,
geoLocation?.ToDmsString(),
face.DateTime,
null,
face.FaceParts,
face.Location,
maker,
null,
model,
face.OutputResolution);
faceFileJson = JsonSerializer.Serialize(faceFile, FaceFileGenerationContext.Default.FaceFile);
using (bitmap = new(width, height))
{
using (graphics = Graphics.FromImage(bitmap))
graphics.DrawImage(source, new Rectangle(0, 0, width, height), rectangle, GraphicsUnit.Pixel);
propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(_ConstructorInfo, artist, type, faceFileJson);
bitmap.SetPropertyItem(propertyItem);
propertyItem = Property.Models.Stateless.IProperty.GetPropertyItem(_ConstructorInfo, userComment, type, faceEncodingJson);
bitmap.SetPropertyItem(propertyItem);
bitmap.Save(fileHolder.FullName, _ImageCodecInfo, _EncoderParameters);
}
if (File.Exists(fileName))
File.Delete(fileName);
location = Shared.Models.Stateless.Methods.ILocation.GetLocation(_FaceDistanceHiddenImageFactor, face.Location, Shared.Models.Stateless.ILocation.Digits, Shared.Models.Stateless.ILocation.Factor, 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 (bitmap = new(width, height))
{
using (graphics = Graphics.FromImage(bitmap))
graphics.DrawImage(source, new Rectangle(0, 0, width, height), rectangle, GraphicsUnit.Pixel);
bitmap.Save(fileName, _HiddenImageCodecInfo, _HiddenEncoderParameters);
}
#pragma warning restore CA1416
File.SetAttributes(fileName, FileAttributes.Hidden);
}
}
}