This commit is contained in:
Mike Phares 2023-12-26 18:27:37 -07:00
parent c2c711673f
commit ec22446643
37 changed files with 1279 additions and 932 deletions

View File

@ -22,6 +22,8 @@
"Hmmssfff",
"jfif",
"JOSN",
"Makernote",
"Makernotes",
"mmod",
"Nicéphore",
"Niépce",
@ -31,6 +33,7 @@
"permyriad",
"Phares",
"Phgtv",
"photoshop",
"RDHC",
"Rects",
"resnet",

View File

@ -8,7 +8,7 @@ using View_by_Distance.Shared.Models.Methods;
namespace View_by_Distance.Distance.Models;
public partial class E_Distance : IDistance<MetadataExtractor.Directory>
public partial class E_Distance : IDistance
{
internal record Record(FilePath FilePath, FaceRecognitionDotNet.FaceEncoding FaceRecognitionDotNetFaceEncoding);
@ -201,7 +201,7 @@ public partial class E_Distance : IDistance<MetadataExtractor.Directory>
}
}
public void LookForMatchFacesAndPossiblyRename(string facesFileNameExtension, FilePath filePath, MappingFromItem mappingFromItem, List<Face> faces, ReadOnlyCollection<LocationContainer<MetadataExtractor.Directory>> locationContainers)
public void LookForMatchFacesAndPossiblyRename(string facesFileNameExtension, FilePath filePath, MappingFromItem mappingFromItem, List<Face> faces, ReadOnlyCollection<LocationContainer> locationContainers)
{
string? json;
string[] matches;
@ -212,20 +212,20 @@ public partial class E_Distance : IDistance<MetadataExtractor.Directory>
Face[] filteredFaces = (from l in faces where l.FaceEncoding is not null && l.Location is not null && l.OutputResolution is not null select l).ToArray();
if (filteredFaces.Length != faces.Count)
checkFaces.Clear();
foreach (LocationContainer<MetadataExtractor.Directory> locationContainer in locationContainers)
foreach (LocationContainer locationContainer in locationContainers)
{
if (_Renamed.Contains(locationContainer.FilePath.FullName))
continue;
if (locationContainer.FromDistanceContent && _DuplicateMappedFaceFiles.Contains(locationContainer.FilePath.Name))
continue;
checkFaces.Clear();
if (locationContainer.Directories.Count == 0)
if (locationContainer.ExifDirectory is null)
{
if (locationContainer.FromDistanceContent)
throw new NullReferenceException(nameof(locationContainer.Directories));
throw new NullReferenceException(nameof(locationContainer.ExifDirectory));
continue;
}
json = Metadata.Models.Stateless.Methods.IMetadata.GetFaceEncoding(locationContainer.Directories);
json = Metadata.Models.Stateless.Methods.IMetadata.GetFaceEncoding(locationContainer.ExifDirectory);
if (json is null)
{
if (_DistanceMoveUnableToMatch)
@ -520,16 +520,16 @@ public partial class E_Distance : IDistance<MetadataExtractor.Directory>
return new(results);
}
ReadOnlyCollection<RelationContainer> IDistance<MetadataExtractor.Directory>.GetRelationContainers(int faceDistancePermyriad, int locationContainerDistanceTake, float locationContainerDistanceTolerance, ReadOnlyCollection<LocationContainer<MetadataExtractor.Directory>> locationContainers)
ReadOnlyCollection<RelationContainer> IDistance.GetRelationContainers(int faceDistancePermyriad, int locationContainerDistanceTake, float locationContainerDistanceTolerance, ReadOnlyCollection<LocationContainer> locationContainers)
{
ReadOnlyCollection<RelationContainer> result;
string? json;
List<Record> records = [];
Shared.Models.FaceEncoding? modelsFaceEncoding;
FaceRecognitionDotNet.FaceEncoding faceRecognitionDotNetFaceEncoding;
foreach (LocationContainer<MetadataExtractor.Directory> locationContainer in locationContainers)
foreach (LocationContainer locationContainer in locationContainers)
{
json = Metadata.Models.Stateless.Methods.IMetadata.GetFaceEncoding(locationContainer.Directories);
json = Metadata.Models.Stateless.Methods.IMetadata.GetFaceEncoding(locationContainer.ExifDirectory);
if (json is null)
continue;
modelsFaceEncoding = JsonSerializer.Deserialize<Shared.Models.FaceEncoding>(json);

View File

@ -7,7 +7,6 @@ using System.Text;
using System.Text.Json;
using View_by_Distance.Drag.Drop.Set.Item.Models;
using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Stateless;
using View_by_Distance.Shared.Models.Stateless.Methods;
namespace View_by_Distance.Drag.Drop.Set.Item;
@ -178,7 +177,7 @@ public partial class DragDropSetPropertyItem : Form
{
short type = 1;
ASCIIEncoding asciiEncoding = new();
int xpKeywords = (int)IExif.Tags.XPKeywords;
int xpKeywords = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagWinKeywords;
ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, [], null) ?? throw new Exception();
List<Record> records = GetRecords(asciiEncoding, xpKeywords, files);
if (records.Count == 0)

View File

@ -162,10 +162,10 @@ public class D_Face
string faceEncodingJson;
PropertyItem? propertyItem;
string outputResolutionJson;
int artist = (int)IExif.Tags.Artist;
int fileSource = (int)IExif.Tags.FileSource;
int userComment = (int)IExif.Tags.UserComment;
using Bitmap source = new(resizedFileHolder.FullName);
int artist = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagArtist;
int fileSource = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagFileSource;
int userComment = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagUserComment;
foreach ((Shared.Models.Face face, FileInfo? fileInfo, string fileName, bool save) in collection)
{
if (!save)
@ -260,9 +260,9 @@ public class D_Face
#pragma warning restore CA1416
private static List<LocationContainer<MetadataExtractor.Directory>> GetLocationContainers(string outputResolution, ReadOnlyCollection<LocationContainer<MetadataExtractor.Directory>> locationContainers, Dictionary<string, int[]> outputResolutionToResize, List<Shared.Models.Face> faces)
private static List<LocationContainer> GetLocationContainers(string outputResolution, ReadOnlyCollection<LocationContainer> locationContainers, Dictionary<string, int[]> outputResolutionToResize, List<Shared.Models.Face> faces)
{
List<LocationContainer<MetadataExtractor.Directory>> results = [];
List<LocationContainer> results = [];
string? json;
Location? location;
Rectangle? rectangle;
@ -275,9 +275,9 @@ public class D_Face
continue;
skip.Add(Shared.Models.Stateless.Methods.ILocation.GetWholePercentages(face.Location, Shared.Models.Stateless.ILocation.Digits, face.OutputResolution));
}
foreach (LocationContainer<MetadataExtractor.Directory> locationContainer in locationContainers)
foreach (LocationContainer locationContainer in locationContainers)
{
if (locationContainer.Directories is null)
if (locationContainer.ExifDirectory is null)
continue;
if (skip.Contains(locationContainer.WholePercentages))
continue;
@ -285,7 +285,7 @@ public class D_Face
{
if (face.Location is not null && face.OutputResolution is not null)
continue;
json = Metadata.Models.Stateless.Methods.IMetadata.GetOutputResolution(locationContainer.Directories);
json = Metadata.Models.Stateless.Methods.IMetadata.GetOutputResolution(locationContainer.ExifDirectory);
if (json is null)
continue;
outputResolutionCheck = JsonSerializer.Deserialize<OutputResolution>(json);
@ -299,7 +299,7 @@ public class D_Face
continue;
if (!results.Any(l => l.WholePercentages == locationContainer.WholePercentages))
results.Add(new(locationContainer.CreationDateOnly,
locationContainer.Directories,
locationContainer.ExifDirectory,
locationContainer.DirectoryNumber,
locationContainer.DisplayDirectoryName,
locationContainer.FilePath,
@ -316,7 +316,7 @@ public class D_Face
return results;
}
public List<Shared.Models.Face> GetFaces(string outputResolution, string dResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, ReadOnlyCollection<LocationContainer<MetadataExtractor.Directory>>? locationContainers, List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection)
public List<Shared.Models.Face> GetFaces(string outputResolution, string dResultsFullGroupDirectory, FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, Shared.Models.Property property, MappingFromItem mappingFromItem, Dictionary<string, int[]> outputResolutionToResize, ReadOnlyCollection<LocationContainer>? locationContainers, List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection)
{
List<Shared.Models.Face>? results;
if (string.IsNullOrEmpty(dResultsFullGroupDirectory))
@ -359,7 +359,7 @@ public class D_Face
parseExceptions.Add(nameof(D_Face));
}
}
List<LocationContainer<MetadataExtractor.Directory>> collection;
List<LocationContainer> collection;
if (results is null || locationContainers is null)
collection = [];
else

View File

@ -788,7 +788,7 @@ public partial class DlibDotNet
_Logger?.LogInformation(string.Concat("Moved <", item.ImageFileHolder.FullName, '>'));
}
private int GetNotMappedCountAndUpdateMappingFromPersonThenSetMapping(MapLogic mapLogic, Item item, bool? isFocusRelativePath, ReadOnlyCollection<LocationContainer<MetadataExtractor.Directory>> locationContainers, MappingFromItem mappingFromItem, List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection, List<Shared.Models.Face> faces)
private int GetNotMappedCountAndUpdateMappingFromPersonThenSetMapping(MapLogic mapLogic, Item item, bool? isFocusRelativePath, ReadOnlyCollection<LocationContainer> locationContainers, MappingFromItem mappingFromItem, List<MappingFromPhotoPrism>? mappingFromPhotoPrismCollection, List<Shared.Models.Face> faces)
{
int result;
double? α;
@ -951,7 +951,7 @@ public partial class DlibDotNet
string[] changesFrom = [nameof(A_Property)];
List<Tuple<string, DateTime>> subFileTuples = [];
FileHolder resizedFileHolder = _Resize.GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber);
ReadOnlyCollection<LocationContainer<MetadataExtractor.Directory>> locationContainers = mapLogic.GetLocationContainers(item);
ReadOnlyCollection<LocationContainer> locationContainers = mapLogic.GetLocationContainers(item);
if (item.Property is null || item.Property.Id is null || !item.SourceDirectoryFileHolder.Exists || item.SourceDirectoryFileHolder.CreationTime is null || item.SourceDirectoryFileHolder.LastWriteTime is null || item.Any())
{
LogItemPropertyIsNull(item);
@ -993,14 +993,14 @@ public partial class DlibDotNet
throw new NullReferenceException(nameof(property));
item.SetResizedFileHolder(_Resize.FileNameExtension, resizedFileHolder);
MappingFromItem mappingFromItem = IMappingFromItem.GetMappingFromItem(containerDateTimes, item, resizedFileHolder);
ExifDirectory exifDirectory = metadata.GetMetadataCollection(item.FilePath, subFileTuples, parseExceptions, changesFrom, mappingFromItem);
Map.Models.Stateless.Methods.IMapLogic.SetCreationTimeMaybeMoveToDecade(_Configuration.PropertyConfiguration, _Configuration.MoveToDecade && _Configuration.LocationContainerDistanceTolerance is null, mappingFromItem, locationContainers);
ReadOnlyDictionary<string, MetadataExtractorDirectory> metadataExtractorDirectories = metadata.GetMetadataCollection(item.FilePath, subFileTuples, parseExceptions, changesFrom, mappingFromItem);
if (_AppSettings.Places.Count > 0)
{
float latitude;
float longitude;
double? distance;
MetadataExtractor.GeoLocation? geoLocation = Metadata.Models.Stateless.Methods.IMetadata.GeoLocation(metadataExtractorDirectories);
MetadataExtractor.GeoLocation? geoLocation = Metadata.Models.Stateless.Methods.IMetadata.GeoLocation(exifDirectory);
foreach (Place place in _AppSettings.Places)
{
if (geoLocation is null)

View File

@ -194,11 +194,11 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
private void LookForAbandoned(Property.Models.Configuration propertyConfiguration, List<int> distinctFilteredIds)
{
List<string> renameCollection = [];
foreach (KeyValuePair<int, List<LocationContainer<MetadataExtractor.Directory>>> keyValuePair in _IdToLocationContainers)
foreach (KeyValuePair<int, List<LocationContainer>> keyValuePair in _IdToLocationContainers)
{
if (distinctFilteredIds.Contains(keyValuePair.Key))
continue;
foreach (LocationContainer<MetadataExtractor.Directory> locationContainer in keyValuePair.Value)
foreach (LocationContainer locationContainer in keyValuePair.Value)
{
if (locationContainer.FilePath.FullName.Contains('!'))
continue;
@ -217,10 +217,10 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
private readonly ReadOnlyDictionary<int, List<int>> _SkipCollection;
private readonly ReadOnlyDictionary<int, List<int>> _SkipNotSkipCollection;
private readonly Shared.Models.Properties.IPropertyConfiguration _PropertyConfiguration;
private readonly ReadOnlyDictionary<int, List<LocationContainer<MetadataExtractor.Directory>>> _IdToLocationContainers;
private readonly ReadOnlyDictionary<int, List<LocationContainer>> _IdToLocationContainers;
private readonly ReadOnlyDictionary<int, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>> _IdThenWholePercentagesToPersonContainers;
public MapLogic(int maxDegreeOfParallelism, Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration? configuration, Shared.Models.Methods.IDistance<MetadataExtractor.Directory> distance, ReadOnlyCollection<PersonContainer> personContainers, long ticks, string? a2PeopleContentDirectory, string a2PeopleSingletonDirectory, string eDistanceContentDirectory)
public MapLogic(int maxDegreeOfParallelism, Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration? configuration, Shared.Models.Methods.IDistance distance, ReadOnlyCollection<PersonContainer> personContainers, long ticks, string? a2PeopleContentDirectory, string a2PeopleSingletonDirectory, string eDistanceContentDirectory)
{
_Ticks = ticks;
_Configuration = configuration;
@ -229,7 +229,7 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
List<PersonContainer> notMappedPersonContainers = [];
Dictionary<int, List<(string, int)>> skipCollection = [];
Dictionary<int, List<(string, int)>> skipNotSkipCollection = [];
List<LocationContainer<MetadataExtractor.Directory>> locationContainers = [];
List<LocationContainer> locationContainers = [];
string? rootDirectoryParent = Path.GetDirectoryName(propertyConfiguration.RootDirectory);
string eDistanceContentTicksDirectory = Path.Combine(eDistanceContentDirectory, ticks.ToString());
ReadOnlyDictionary<int, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>> idThenWholePercentagesToPersonContainers;
@ -332,14 +332,14 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
return result;
}
public ReadOnlyCollection<LocationContainer<MetadataExtractor.Directory>> GetLocationContainers(Item item)
public ReadOnlyCollection<LocationContainer> GetLocationContainers(Item item)
{
LocationContainer<MetadataExtractor.Directory>[] results;
LocationContainer[] results;
if (item.Property?.Id is null)
results = [];
else
{
List<LocationContainer<MetadataExtractor.Directory>>? locationContainers;
List<LocationContainer>? locationContainers;
if (_IdToLocationContainers.TryGetValue(item.Property.Id.Value, out locationContainers))
results = locationContainers.ToArray();
else
@ -678,17 +678,17 @@ public partial class MapLogic : Shared.Models.Methods.IMapLogic
if (j == i)
continue;
if (face.Mapping.MappingFromFilterPre.InSkipCollection is not null && face.Mapping.MappingFromFilterPre.InSkipCollection.Value)
throw new NotSupportedException(nameof(Shared.Models.Methods.IDistance<object>));
throw new NotSupportedException(nameof(Shared.Models.Methods.IDistance));
if (face.Mapping.MappingFromFilterPre.IsFocusModel is not null && !face.Mapping.MappingFromFilterPre.IsFocusModel.Value)
throw new NotSupportedException(nameof(Shared.Models.Methods.IDistance<object>));
throw new NotSupportedException(nameof(Shared.Models.Methods.IDistance));
if (face.Mapping.MappingFromFilterPre.IsFocusRelativePath is not null && !face.Mapping.MappingFromFilterPre.IsFocusRelativePath.Value)
throw new NotSupportedException(nameof(Shared.Models.Methods.IDistance<object>));
throw new NotSupportedException(nameof(Shared.Models.Methods.IDistance));
if (face.Mapping.MappingFromFilterPost.InSkipCollection is not null && face.Mapping.MappingFromFilterPost.InSkipCollection.Value)
throw new NotSupportedException(nameof(Shared.Models.Methods.IDistance<object>));
throw new NotSupportedException(nameof(Shared.Models.Methods.IDistance));
if (face.Mapping.MappingFromFilterPost.IsFocusPerson is not null && !face.Mapping.MappingFromFilterPost.IsFocusPerson.Value)
throw new NotSupportedException(nameof(Shared.Models.Methods.IDistance<object>));
throw new NotSupportedException(nameof(Shared.Models.Methods.IDistance));
if (face.Mapping.MappingFromFilterPost.InSkipCollection is not null && face.Mapping.MappingFromFilterPost.InSkipCollection.Value)
throw new NotSupportedException(nameof(Shared.Models.Methods.IDistance<object>));
throw new NotSupportedException(nameof(Shared.Models.Methods.IDistance));
faceDistanceLength = faceDistanceLengths[j];
if (faceDistanceLength.WholePercentages is null || faceDistanceLength.Length is null)
throw new NotSupportedException();

View File

@ -32,7 +32,7 @@ internal abstract class DecadeLogic
return result;
}
internal static void SetCreationTimeMaybeMoveToDecade(Property.Models.Configuration propertyConfiguration, bool moveToDecade, MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer<MetadataExtractor.Directory>> locationContainers)
internal static void SetCreationTimeMaybeMoveToDecade(Property.Models.Configuration propertyConfiguration, bool moveToDecade, MappingFromItem mappingFromItem, ReadOnlyCollection<LocationContainer> locationContainers)
{
DateTime dateTime;
string halfDecade;
@ -42,7 +42,7 @@ internal abstract class DecadeLogic
string personNameDirectoryName;
string? personKeyFormattedDirectory;
string? personKeyFormattedDirectoryName;
foreach (LocationContainer<MetadataExtractor.Directory> locationContainer in locationContainers)
foreach (LocationContainer locationContainer in locationContainers)
{
if (!File.Exists(locationContainer.FilePath.FullName))
continue;

View File

@ -470,7 +470,7 @@ internal abstract class MapLogic
return results;
}
private static void ParallelFor(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, Dictionary<int, List<(string, int)>> skipCollection, List<LocationContainer<MetadataExtractor.Directory>> locationContainers, MappedFile mappedFile)
private static void ParallelFor(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, Dictionary<int, List<(string, int)>> skipCollection, List<LocationContainer> locationContainers, MappedFile mappedFile)
{
int? id;
string checkFile;
@ -480,9 +480,9 @@ internal abstract class MapLogic
FileHolder fileHolder;
int? wholePercentages;
const string lnk = ".lnk";
ExifDirectory? exifDirectory;
string personDisplayDirectoryName;
const bool fromDistanceContent = true;
IReadOnlyList<MetadataExtractor.Directory> directories;
List<(string File, int WholePercentages)>? wholePercentagesCollection;
if (!mappedFile.FilePath.Name.EndsWith(lnk))
{
@ -518,14 +518,14 @@ internal abstract class MapLogic
}
dateOnly = DateOnly.FromDateTime(new DateTime(mappedFile.FilePath.CreationTicks));
if (mappedFile.FilePath.Name.EndsWith(lnk) || (!configuration.DistanceMoveUnableToMatch && !configuration.DistanceRenameToMatch) || !File.Exists(mappedFile.FilePath.FullName))
directories = new List<MetadataExtractor.Directory>();
exifDirectory = null;
else
directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(mappedFile.FilePath.FullName);
exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(mappedFile.FilePath);
RectangleF? rectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, wholePercentages.Value);
personDisplayDirectoryName = mappedFile.PersonDisplayDirectoryName is null ? configuration.MappingDefaultName : mappedFile.PersonDisplayDirectoryName;
lock (locationContainers)
locationContainers.Add(new(dateOnly,
directories,
exifDirectory,
mappedFile.DirectoryNumber,
personDisplayDirectoryName,
mappedFile.FilePath,
@ -537,7 +537,7 @@ internal abstract class MapLogic
wholePercentages.Value));
}
private static void LookForPossibleDuplicates(Configuration configuration, ReadOnlyCollection<LocationContainer<MetadataExtractor.Directory>> locationContainers)
private static void LookForPossibleDuplicates(Configuration configuration, ReadOnlyCollection<LocationContainer> locationContainers)
{
string key;
float? percent;
@ -547,7 +547,7 @@ internal abstract class MapLogic
RectangleF? itemPercentagesRectangle;
(FilePath FilePath, int WholePercentages) item;
Dictionary<string, (FilePath, int)> distinct = [];
foreach (LocationContainer<MetadataExtractor.Directory> locationContainer in locationContainers)
foreach (LocationContainer locationContainer in locationContainers)
{
key = string.Concat(locationContainer.PersonKey, locationContainer.Id);
if (distinct.TryGetValue(key, out item))
@ -890,9 +890,9 @@ internal abstract class MapLogic
}
}
internal static List<LocationContainer<MetadataExtractor.Directory>> GetLocationContainers(int maxDegreeOfParallelism, Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, Dictionary<int, List<(string, int)>> skipCollection, List<Record> records)
internal static List<LocationContainer> GetLocationContainers(int maxDegreeOfParallelism, Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, Dictionary<int, List<(string, int)>> skipCollection, List<Record> records)
{
List<LocationContainer<MetadataExtractor.Directory>> results = [];
List<LocationContainer> results = [];
List<MappedFile> mappedFiles = GetMappedFiles(propertyConfiguration, configuration, personContainers, records);
if (mappedFiles.Count > 0 && (configuration.DistanceMoveUnableToMatch || configuration.DistanceRenameToMatch))
{
@ -909,7 +909,7 @@ internal abstract class MapLogic
}
if (string.IsNullOrEmpty(configuration.LocationContainerDebugDirectory))
{
ReadOnlyCollection<LocationContainer<MetadataExtractor.Directory>> locationContainers = new(results.OrderBy(l => l.DirectoryNumber).ToArray());
ReadOnlyCollection<LocationContainer> locationContainers = new(results.OrderBy(l => l.DirectoryNumber).ToArray());
LookForPossibleDuplicates(configuration, locationContainers);
}
return results;
@ -1248,10 +1248,10 @@ internal abstract class MapLogic
return new(results);
}
internal static ReadOnlyDictionary<int, List<LocationContainer<MetadataExtractor.Directory>>> ConvertLocationContainers(List<LocationContainer<MetadataExtractor.Directory>> locationContainers)
internal static ReadOnlyDictionary<int, List<LocationContainer>> ConvertLocationContainers(List<LocationContainer> locationContainers)
{
Dictionary<int, List<LocationContainer<MetadataExtractor.Directory>>> results = [];
foreach (LocationContainer<MetadataExtractor.Directory> locationContainer in locationContainers)
Dictionary<int, List<LocationContainer>> results = [];
foreach (LocationContainer locationContainer in locationContainers)
{
if (!results.ContainsKey(locationContainer.Id))
results.Add(locationContainer.Id, []);

View File

@ -35,9 +35,9 @@ public interface IMapLogic
static List<(string, long)> GetJLinkDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat, char[] personCharacters, string a2PeopleSingletonDirectory, string a2PeopleContentDirectory) =>
MapLogic.GetJLinkDirectories(genealogicalDataCommunicationFile, jLinks, personBirthdayFormat, personCharacters, a2PeopleSingletonDirectory, a2PeopleContentDirectory);
void TestStatic_SetCreationTimeMaybeMoveToDecade(Property.Models.Configuration propertyConfiguration, bool moveToDecade, Shared.Models.MappingFromItem mappingFromItem, ReadOnlyCollection<Shared.Models.LocationContainer<MetadataExtractor.Directory>> locationContainers) =>
void TestStatic_SetCreationTimeMaybeMoveToDecade(Property.Models.Configuration propertyConfiguration, bool moveToDecade, Shared.Models.MappingFromItem mappingFromItem, ReadOnlyCollection<Shared.Models.LocationContainer> locationContainers) =>
SetCreationTimeMaybeMoveToDecade(propertyConfiguration, moveToDecade, mappingFromItem, locationContainers);
static void SetCreationTimeMaybeMoveToDecade(Property.Models.Configuration propertyConfiguration, bool moveToDecade, Shared.Models.MappingFromItem mappingFromItem, ReadOnlyCollection<Shared.Models.LocationContainer<MetadataExtractor.Directory>> locationContainers) =>
static void SetCreationTimeMaybeMoveToDecade(Property.Models.Configuration propertyConfiguration, bool moveToDecade, Shared.Models.MappingFromItem mappingFromItem, ReadOnlyCollection<Shared.Models.LocationContainer> locationContainers) =>
DecadeLogic.SetCreationTimeMaybeMoveToDecade(propertyConfiguration, moveToDecade, mappingFromItem, locationContainers);
bool? TestStatic_CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<Shared.Models.PersonContainer>>? wholePercentagesToPersonContainers, Shared.Models.MappingFromLocation mappingFromLocation) =>

View File

@ -8,14 +8,14 @@ namespace View_by_Distance.Map.Models.Stateless;
internal abstract class RelationLogic
{
internal record Group(string Key, long PersonKey, ReadOnlyCollection<LocationContainer<MetadataExtractor.Directory>> RelationContainersCollection);
internal record Group(string Key, long PersonKey, ReadOnlyCollection<LocationContainer> RelationContainersCollection);
private static Dictionary<long, Dictionary<int, List<LocationContainer<MetadataExtractor.Directory>>>> GetPersonKeyTo(Configuration configuration, List<LocationContainer<MetadataExtractor.Directory>> locationContainers)
private static Dictionary<long, Dictionary<int, List<LocationContainer>>> GetPersonKeyTo(Configuration configuration, List<LocationContainer> locationContainers)
{
List<LocationContainer<MetadataExtractor.Directory>>? collection;
Dictionary<int, List<LocationContainer<MetadataExtractor.Directory>>>? yearTo;
Dictionary<long, Dictionary<int, List<LocationContainer<MetadataExtractor.Directory>>>> personKeyTo = [];
foreach (LocationContainer<MetadataExtractor.Directory> locationContainer in locationContainers)
List<LocationContainer>? collection;
Dictionary<int, List<LocationContainer>>? yearTo;
Dictionary<long, Dictionary<int, List<LocationContainer>>> personKeyTo = [];
foreach (LocationContainer locationContainer in locationContainers)
{
if (!locationContainer.FromDistanceContent)
continue;
@ -38,7 +38,7 @@ internal abstract class RelationLogic
return personKeyTo;
}
private static ReadOnlyCollection<Group> GetGroups(Configuration configuration, List<LocationContainer<MetadataExtractor.Directory>> locationContainers)
private static ReadOnlyCollection<Group> GetGroups(Configuration configuration, List<LocationContainer> locationContainers)
{
List<Group> results = [];
string key;
@ -46,10 +46,10 @@ internal abstract class RelationLogic
List<int> years = [];
List<int> indices = [];
List<(int Index, int Year)> sort = [];
List<LocationContainer<MetadataExtractor.Directory>> collection = [];
KeyValuePair<int, List<LocationContainer<MetadataExtractor.Directory>>> keyValue;
Dictionary<long, Dictionary<int, List<LocationContainer<MetadataExtractor.Directory>>>> personKeyTo = GetPersonKeyTo(configuration, locationContainers);
foreach (KeyValuePair<long, Dictionary<int, List<LocationContainer<MetadataExtractor.Directory>>>> keyValuePair in personKeyTo)
List<LocationContainer> collection = [];
KeyValuePair<int, List<LocationContainer>> keyValue;
Dictionary<long, Dictionary<int, List<LocationContainer>>> personKeyTo = GetPersonKeyTo(configuration, locationContainers);
foreach (KeyValuePair<long, Dictionary<int, List<LocationContainer>>> keyValuePair in personKeyTo)
{
sort.Clear();
years.Clear();
@ -403,7 +403,7 @@ internal abstract class RelationLogic
}
}
internal static void SaveMappedRelations(Configuration configuration, Shared.Models.Methods.IDistance<MetadataExtractor.Directory> distance, string a2PeopleContentDirectory, string eDistanceContentDirectory, long ticks, List<LocationContainer<MetadataExtractor.Directory>> locationContainers, ReadOnlyDictionary<string, PersonContainer> readOnlyPersonKeyFormattedToPersonContainer, ReadOnlyDictionary<long, List<PersonContainer>> readOnlyPersonKeyToPersonContainerCollection)
internal static void SaveMappedRelations(Configuration configuration, Shared.Models.Methods.IDistance distance, string a2PeopleContentDirectory, string eDistanceContentDirectory, long ticks, List<LocationContainer> locationContainers, ReadOnlyDictionary<string, PersonContainer> readOnlyPersonKeyFormattedToPersonContainer, ReadOnlyDictionary<long, List<PersonContainer>> readOnlyPersonKeyToPersonContainerCollection)
{
int take;
string directory;

View File

@ -42,6 +42,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Property\Property.csproj" />
<ProjectReference Include="..\Metadata\Metadata.csproj" />
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
</ItemGroup>
<ItemGroup>

View File

@ -4,8 +4,8 @@ using Phares.Shared;
using ShellProgressBar;
using System.Collections.ObjectModel;
using System.Text;
using System.Text.Json;
using View_by_Distance.Metadata.Query.Models;
using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Methods;
namespace View_by_Distance.Metadata.Query;
@ -56,18 +56,18 @@ public class MetadataQuery
{ }
}
private List<(string FileName, string Count, string TagGroup, string TagIdName, string Value)> GetCollection(long ticks)
private List<(string FileName, string TagGroup, string TagIdName, string Value)> GetCollection(long ticks)
{
int count;
string json;
string message;
string fileName;
FileInfo fileInfo;
FilePath filePath;
FileHolder fileHolder;
ProgressBar progressBar;
ExifDirectory exifDirectory;
const string fileSearchFilter = "*";
const bool useCeilingAverage = true;
const string directorySearchFilter = "*";
Dictionary<string, List<KeyValuePair<string, string>>>? dictionary;
List<(string FileName, string Count, string TagGroup, string TagIdName, string Value)> collection = [];
List<(string FileName, string TagGroup, string TagIdName, string Value)> collection = [];
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
ReadOnlyCollection<string[]> filesCollection = Shared.Models.Stateless.Methods.IDirectory.GetFilesCollection(_PropertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter, useCeilingAverage);
foreach (string[] files in filesCollection)
@ -78,57 +78,33 @@ public class MetadataQuery
progressBar = new(files.Length, message, options);
foreach (string file in files)
{
count = 0;
progressBar.Tick();
json = File.ReadAllText(file);
fileName = Path.GetFileName(file);
dictionary = JsonSerializer.Deserialize<Dictionary<string, List<KeyValuePair<string, string>>>>(json);
if (dictionary is null)
continue;
foreach (KeyValuePair<string, List<KeyValuePair<string, string>>> keyValuePair in dictionary)
{
foreach (KeyValuePair<string, string> keyValue in keyValuePair.Value)
count++;
}
foreach (KeyValuePair<string, List<KeyValuePair<string, string>>> keyValuePair in dictionary)
{
foreach (KeyValuePair<string, string> keyValue in keyValuePair.Value)
collection.Add(new(fileName, count.ToString("000000"), keyValuePair.Key, keyValue.Key, keyValue.Value));
}
fileInfo = new(file);
fileHolder = FileHolder.Get(fileInfo);
filePath = FilePath.Get(_PropertyConfiguration, fileHolder, index: null);
exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(filePath);
// exifDirectory.ExifDirectoryBase.Artist;
// exifDirectory.ExifDirectoryBase.WinComment;
// exifDirectory.ExifDirectoryBase.Model;
// exifDirectory.ExifDirectoryBase.CameraOwnerName;
// exifDirectory.ExifDirectoryBase.Make;
// exifDirectory.ExifDirectoryBase.BodySerialNumber;
// exifDirectory.ExifDirectoryBase.LensSerialNumber;
// exifDirectory.ExifDirectoryBase.Software;
// collection.Add(new(fileInfo.Name, keyValuePair.Key, keyValue.Key, keyValue.Value));
}
progressBar.Dispose();
}
return collection;
}
private static Dictionary<string, List<string>> GetKeyValuePairs(List<(string FileName, string Count, string TagGroup, string TagIdName, string Value)> matches)
{
string key;
string line;
List<string>? valuePairs;
Dictionary<string, List<string>> keyValuePairs = [];
foreach ((string fileName, string count, string tagGroup, string tagIdName, string value) in matches)
{
key = $"{tagGroup}\t{tagIdName}\t{value.Trim()}";
line = $"{tagGroup}\t{tagIdName}\t{value.Trim()}\t{count}\t{fileName}";
if (!keyValuePairs.TryGetValue(key, out valuePairs))
{
keyValuePairs.Add(key, []);
if (!keyValuePairs.TryGetValue(key, out valuePairs))
throw new Exception();
}
valuePairs.Add(line);
}
return keyValuePairs;
}
private void MetadataQueryFilesInDirectories(ILogger<Program>? logger, long ticks)
{
List<(string FileName, string Count, string TagGroup, string TagIdName, string Value)> collection = GetCollection(ticks);
List<(string FileName, string TagGroup, string TagIdName, string Value)> collection = GetCollection(ticks);
logger?.LogInformation($"Ready to query {collection.Count} entries?");
IEnumerable<(string FileName, string Count, string TagGroup, string TagIdName, string Value)> enumerable()
IEnumerable<(string FileName, string TagGroup, string TagIdName, string Value)> enumerable()
{
foreach ((string FileName, string Count, string TagGroup, string TagIdName, string Value) l in collection)
foreach ((string FileName, string TagGroup, string TagIdName, string Value) l in collection)
{
if (l.TagIdName.StartsWith("42016\t") && l.Value != "00000000000000000000000000000000")
{
@ -136,19 +112,18 @@ public class MetadataQuery
}
}
}
List<(string FileName, string Count, string TagGroup, string TagIdName, string Value)> matches = enumerable().ToList();
List<(string FileName, string TagGroup, string TagIdName, string Value)> matches = enumerable().ToList();
if (matches.Count != 0)
{
matches.Sort();
StringBuilder stringBuilder = new();
Dictionary<string, List<string>> keyValuePairs = GetKeyValuePairs(matches);
foreach (KeyValuePair<string, List<string>> keyValuePair in keyValuePairs)
{
if (keyValuePair.Value.Count != 2)
continue;
foreach (string line in keyValuePair.Value)
_ = stringBuilder.AppendLine(line);
}
// foreach (KeyValuePair<string, List<string>> keyValuePair in keyValuePairs)
// {
// if (keyValuePair.Value.Count != 2)
// continue;
// foreach (string line in keyValuePair.Value)
// _ = stringBuilder.AppendLine(line);
// }
string checkFile = $"D:/Tmp/Phares/{DateTime.Now.Ticks}.tsv";
string text = stringBuilder.ToString();
_ = Shared.Models.Stateless.Methods.IPath.WriteAllText(checkFile, text, updateToWhenMatches: null, compareBeforeWrite: true, updateDateWhenMatches: false);

View File

@ -39,14 +39,13 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
public override string ToString()
{
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
string result = JsonSerializer.Serialize(this, _WriteIndentedJsonSerializerOptions);
return result;
}
public ReadOnlyDictionary<string, MetadataExtractorDirectory> GetMetadataCollection(FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, string[] changesFrom, MappingFromItem mappingFromItem)
public ExifDirectory GetMetadataCollection(FilePath filePath, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions, string[] changesFrom, MappingFromItem mappingFromItem)
{
Dictionary<string, MetadataExtractorDirectory>? results = null;
string json = string.Empty;
ExifDirectory? result = null;
List<DateTime> dateTimes = (from l in subFileTuples where changesFrom.Contains(l.Item1) select l.Item2).ToList();
(_, int directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration, filePath);
FileInfo fileInfo = new(Path.Combine(_FileGroups[_PropertyConfiguration.ResultSingleton][directoryIndex], $"{mappingFromItem.ImageFileHolder.NameWithoutExtension}{mappingFromItem.ImageFileHolder.ExtensionLowered}.json"));
@ -61,34 +60,33 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
fileInfo.Refresh();
}
if (_PropertiesChangedForMetadata)
results = null;
result = null;
else if (!fileInfo.Exists)
results = null;
result = null;
else if (!fileInfo.FullName.EndsWith(".json") && !fileInfo.FullName.EndsWith(".old"))
throw new ArgumentException("must be a *.json file");
else if (dateTimes.Count != 0 && dateTimes.Max() > fileInfo.LastWriteTime)
results = null;
result = null;
else
{
json = File.ReadAllText(fileInfo.FullName);
string json = File.ReadAllText(fileInfo.FullName);
try
{
results = Stateless.Methods.Metadata.Deserialize(json);
if (results is null)
result = JsonSerializer.Deserialize(json, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
if (result is null)
throw new Exception();
subFileTuples.Add(new Tuple<string, DateTime>(nameof(B_Metadata), fileInfo.LastWriteTime));
}
catch (Exception)
{
results = null;
result = null;
parseExceptions.Add(nameof(B_Metadata));
}
}
if (results is null || results.Count == 0)
if (result is null)
{
IReadOnlyList<MetadataExtractor.Directory> directories = ImageMetadataReader.ReadMetadata(mappingFromItem.ImageFileHolder.FullName);
results = Stateless.Methods.Metadata.GetKeyValuePairs(directories);
json = JsonSerializer.Serialize(results, DictionaryStringMetadataExtractorDirectorySourceGenerationContext.Default.DictionaryStringMetadataExtractorDirectory);
result = Stateless.Methods.IMetadata.GetExifDirectory(filePath);
string json = JsonSerializer.Serialize(result, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
bool updateDateWhenMatches = dateTimes.Count != 0 && fileInfo.Exists && dateTimes.Max() > fileInfo.LastWriteTime;
DateTime? dateTime = !updateDateWhenMatches ? null : dateTimes.Max();
if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches, compareBeforeWrite: true, updateToWhenMatches: dateTime))
@ -103,7 +101,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
}
}
}
return new(results);
return result;
}
(DateTime?, DateTime?[]) IMetadata<MetadataExtractor.Directory>.GetDateTimes(FileHolder fileHolder, IReadOnlyList<MetadataExtractor.Directory> directories)
@ -203,7 +201,7 @@ public class B_Metadata : IMetadata<MetadataExtractor.Directory>
}
}
}
return new(result, results.ToArray());
return new(result, [.. results]);
}
}

View File

@ -1,194 +0,0 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace View_by_Distance.Metadata.Models;
public record Exif(string? InteropIndex1,
string? Noise37389,
string? FocalPlaneXResolutionTiffEp37390,
string? FocalPlaneYResolutionTiffEp37391,
string? ImageNumber37393,
string? SecurityClassification37394,
string? ImageHistory37395,
string? SubjectLocationTiffEp37396,
string? ExposureIndexTiffEp37397,
string? SpatialFreqResponseTiffEp37388,
string? StandardIdTiffEp37398,
string? UserComment37510,
string? SubsecondTime37520,
string? SubsecondTimeOriginal37521,
string? SubsecondTimeDigitized37522,
string? WinTitle40091,
string? WinComment40092,
string? WinAuthor40093,
string? WinKeywords40094,
string? Makernote37500,
string? WinSubject40095,
string? FlashEnergyTiffEp37387,
string? Flash37385,
string? IsoSpeedLatitudeYYY34868,
string? IsoSpeedLatitudeZZZ34869,
string? ExifVersion36864,
string? DateTimeOriginal36867,
string? DateTimeDigitized36868,
string? TimeZone36880,
string? TimeZoneOriginal36881,
string? TimeZoneDigitized36882,
string? FocalLength37386,
string? ComponentsConfiguration37121,
string? ShutterSpeed37377,
string? Aperture37378,
string? BrightnessValue37379,
string? ExposureBias37380,
string? MaxAperture37381,
string? SubjectDistance37382,
string? MeteringMode37383,
string? WhiteBalance37384,
string? CompressedAverageBitsPerPixel37122,
string? IsoSpeed34867,
string? FlashpixVersion40960,
string? ExifImageWidth40962,
string? Sharpness41994,
string? DeviceSettingDescription41995,
string? SubjectDistanceRange41996,
string? ImageUniqueId42016,
string? CameraOwnerName42032,
string? BodySerialNumber42033,
string? LensSpecification42034,
string? LensMake42035,
string? Saturation41993,
string? LensModel42036,
string? GdalMetadata42112,
string? GdalNoData42113,
string? Gamma42240,
string? PrintImageMatchingInfo50341,
string? PanasonicTitle50898,
string? PanasonicTitle250899,
string? Padding59932,
string? Lens65002,
string? LensSerialNumber42037,
string? ColorSpace40961,
string? Contrast41992,
string? SceneCaptureType41990,
string? ExifImageHeight40963,
string? RelatedSoundFile40964,
string? FlashEnergy41483,
string? SpatialFreqResponse41484,
string? FocalPlaneXResolution41486,
string? FocalPlaneYResolution41487,
string? FocalPlaneResolutionUnit41488,
string? SubjectLocation41492,
string? GainControl41991,
string? ExposureIndex41493,
string? FileSource41728,
string? SceneType41729,
string? CfaPattern41730,
string? CustomRendered41985,
string? ExposureMode41986,
string? WhiteBalanceMode41987,
string? DigitalZoomRatio41988,
string? Film35MMEquivFocalLength41989,
string? SensingMethod41495,
string? RecommendedExposureIndex34866,
string? StandardOutputSensitivity34865,
string? SensitivityType34864,
string? YResolution283,
string? PlanarConfiguration284,
string? PageName285,
string? ResolutionUnit296,
string? PageNumber297,
string? TransferFunction301,
string? Software305,
string? DateTime306,
string? XResolution282,
string? Artist315,
string? Predictor317,
string? WhitePoint318,
string? PrimaryChromaticities319,
string? TileWidth322,
string? TileLength323,
string? TileOffsets324,
string? TileByteCounts325,
string? SubIfdOffset330,
string? HostComputer316,
string? ExtraSamples338,
string? MaxSampleValue281,
string? StripByteCounts279,
string? InteropVersion2,
string? NewSubfileType254,
string? SubfileType255,
string? ImageWidth256,
string? ImageHeight257,
string? BitsPerSample258,
string? Compression259,
string? PhotometricInterpretation262,
string? MinSampleValue280,
string? Thresholding263,
string? DocumentName269,
string? ImageDescription270,
string? Make271,
string? Model272,
string? StripOffsets273,
string? Orientation274,
string? SamplesPerPixel277,
string? RowsPerStrip278,
string? FillOrder266,
string? SampleFormat339,
string? TransferRange342,
string? JpegTables347,
string? FNumber33437,
string? PixelScale33550,
string? IptcNaa33723,
string? ModelTiePoint33922,
string? PhotoshopSettings34377,
string? InterColorProfile34675,
string? GeoTiffGeoKeys34735,
string? GeoTiffGeoDoubleParams34736,
string? ExposureTime33434,
string? GeoTiffGeoAsciiParams34737,
string? SpectralSensitivity34852,
string? IsoEquivalent34855,
string? OptoElectricConversionFunction34856,
string? Interlace34857,
string? TimeZoneOffsetTiffEp34858,
string? SelfTimerModeTiffEp34859,
string? TimeZoneOffset34858,
string? SelfTimerMode34859,
string? ExposureProgram34850,
string? Copyright33432,
string? BatteryLevel33423,
string? CfaPattern233422,
string? JpegProc512,
string? JpegRestartInterval515,
string? JpegLosslessPredictors517,
string? JpegPointTransforms518,
string? JpegQTables519,
string? JpegDcTables520,
string? JpegAcTables521,
string? YCbCrCoefficients529,
string? YCbCrSubsampling530,
string? YCbCrPositioning531,
string? ReferenceBlackWhite532,
string? StripRowCounts559,
string? ApplicationNotes700,
string? RelatedImageFileFormat4096,
string? RelatedImageWidth4097,
string? RelatedImageHeight4098,
string? Rating18246,
string? RatingPercent18249,
string? CfaRepeatPatternDim33421)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, ExifSourceGenerationContext.Default.Exif);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Exif))]
public partial class ExifSourceGenerationContext : JsonSerializerContext
{
}

View File

@ -1,43 +0,0 @@
using System.Collections.ObjectModel;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace View_by_Distance.Metadata.Models;
public record MetadataExtractorDirectory(string Name,
bool HasError,
ReadOnlyCollection<string> Errors,
ReadOnlyDictionary<int, MetadataExtractorTag> Tags)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, MetadataExtractorDirectorySourceGenerationContext.Default.MetadataExtractorDirectory);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(MetadataExtractorDirectory))]
public partial class MetadataExtractorDirectorySourceGenerationContext : JsonSerializerContext
{
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(List<MetadataExtractorDirectory>))]
public partial class MetadataExtractorDirectoryCollectionSourceGenerationContext : JsonSerializerContext
{
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Dictionary<string, MetadataExtractorDirectory>))]
public partial class DictionaryStringMetadataExtractorDirectorySourceGenerationContext : JsonSerializerContext
{
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(ReadOnlyDictionary<string, MetadataExtractorDirectory>))]
public partial class ReadOnlyDictionaryStringMetadataExtractorDirectorySourceGenerationContext : JsonSerializerContext
{
}

View File

@ -1,43 +0,0 @@
using System.Collections.ObjectModel;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace View_by_Distance.Metadata.Models;
public record MetadataExtractorTag(int Type,
string? Description,
bool HasName,
string Name)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, MetadataExtractorTagSourceGenerationContext.Default.MetadataExtractorTag);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(MetadataExtractorTag))]
public partial class MetadataExtractorTagSourceGenerationContext : JsonSerializerContext
{
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(List<MetadataExtractorTag>))]
public partial class MetadataExtractorTagCollectionSourceGenerationContext : JsonSerializerContext
{
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Dictionary<string, MetadataExtractorTag>))]
public partial class DictionaryStringMetadataExtractorTagSourceGenerationContext : JsonSerializerContext
{
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(ReadOnlyDictionary<string, MetadataExtractorTag>))]
public partial class ReadOnlyDictionaryStringMetadataExtractorTagSourceGenerationContext : JsonSerializerContext
{
}

View File

@ -1,24 +0,0 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace View_by_Distance.Metadata.Models.Stateless.Methods;
internal record Record(string Name,
bool HasError,
List<string> Errors,
Dictionary<int, MetadataExtractorTag> Tags)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, RecordSourceGenerationContext.Default.Record);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Record))]
internal partial class RecordSourceGenerationContext : JsonSerializerContext
{
}

View File

@ -0,0 +1,54 @@
using View_by_Distance.Shared.Models;
namespace View_by_Distance.Metadata.Models.Stateless.Methods;
internal static class Base
{
internal static string GetMaker(ExifDirectoryBase[]? exifBaseDirectories)
{
string? result = null;
if (exifBaseDirectories is not null)
{
string value;
foreach (ExifDirectoryBase exifDirectoryBase in exifBaseDirectories)
{
value = exifDirectoryBase?.Make is null ? string.Empty : exifDirectoryBase.Make.ToString().Trim();
if (string.IsNullOrEmpty(value))
result = null;
else
{
result = $"{value[0].ToString().ToUpper()}{value[1..].ToLower()}";
break;
}
}
}
if (string.IsNullOrEmpty(result))
result = "Unknown";
return result;
}
internal static string GetModel(ExifDirectoryBase[]? exifBaseDirectories)
{
string? result = null;
if (exifBaseDirectories is not null)
{
string value;
foreach (ExifDirectoryBase exifDirectoryBase in exifBaseDirectories)
{
value = exifDirectoryBase?.Model is null ? string.Empty : exifDirectoryBase.Model.ToString().Trim();
if (string.IsNullOrEmpty(value))
result = null;
else
{
result = value;
break;
}
}
}
if (string.IsNullOrEmpty(result))
result = "Unknown";
return result;
}
}

View File

@ -0,0 +1,126 @@
using System.Drawing;
namespace View_by_Distance.Metadata.Models.Stateless.Methods;
internal static class Dimensions
{
#pragma warning disable IDE0230
private static readonly Dictionary<byte[], Func<BinaryReader, Size?>> _ImageFormatDecoders = new()
{
{ new byte[] { 0x42, 0x4D }, DecodeBitmap },
{ new byte[] { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }, DecodeGif },
{ new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, DecodeGif },
{ new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, DecodePng },
{ new byte[] { 0xff, 0xd8 }, DecodeJfif },
{ new byte[] { 0x52, 0x49, 0x46, 0x46 }, DecodeWebP },
};
#pragma warning restore IDE0230
private static bool StartsWith(byte[] thisBytes, byte[] thatBytes)
{
for (int i = 0; i < thatBytes.Length; i += 1)
{
if (thisBytes[i] == thatBytes[i])
continue;
return false;
}
return true;
}
private static short ReadLittleEndianInt16(BinaryReader binaryReader)
{
byte[] bytes = new byte[sizeof(short)];
for (int i = 0; i < sizeof(short); i += 1)
bytes[sizeof(short) - 1 - i] = binaryReader.ReadByte();
return BitConverter.ToInt16(bytes, 0);
}
private static int ReadLittleEndianInt32(BinaryReader binaryReader)
{
byte[] bytes = new byte[sizeof(int)];
for (int i = 0; i < sizeof(int); i += 1)
bytes[sizeof(int) - 1 - i] = binaryReader.ReadByte();
return BitConverter.ToInt32(bytes, 0);
}
private static Size? DecodeBitmap(BinaryReader binaryReader)
{
_ = binaryReader.ReadBytes(16);
int width = binaryReader.ReadInt32();
int height = binaryReader.ReadInt32();
return new Size(width, height);
}
private static Size? DecodeGif(BinaryReader binaryReader)
{
int width = binaryReader.ReadInt16();
int height = binaryReader.ReadInt16();
return new Size(width, height);
}
private static Size? DecodePng(BinaryReader binaryReader)
{
_ = binaryReader.ReadBytes(8);
int width = ReadLittleEndianInt32(binaryReader);
int height = ReadLittleEndianInt32(binaryReader);
return new Size(width, height);
}
private static Size? DecodeJfif(BinaryReader binaryReader)
{
while (binaryReader.ReadByte() == 0xff)
{
byte marker = binaryReader.ReadByte();
short chunkLength = ReadLittleEndianInt16(binaryReader);
if (marker == 0xc0)
{
_ = binaryReader.ReadByte();
int height = ReadLittleEndianInt16(binaryReader);
int width = ReadLittleEndianInt16(binaryReader);
return new Size(width, height);
}
if (chunkLength >= 0)
_ = binaryReader.ReadBytes(chunkLength - 2);
else
{
ushort uChunkLength = (ushort)chunkLength;
_ = binaryReader.ReadBytes(uChunkLength - 2);
}
}
return null;
}
private static Size? DecodeWebP(BinaryReader binaryReader)
{
_ = binaryReader.ReadUInt32(); // Size
_ = binaryReader.ReadBytes(15); // WEBP, VP8 + more
_ = binaryReader.ReadBytes(3); // SYNC
int width = binaryReader.ReadUInt16() & 0b00_11111111111111; // 14 bits width
int height = binaryReader.ReadUInt16() & 0b00_11111111111111; // 14 bits height
return new Size(width, height);
}
internal static Size? GetDimensions(BinaryReader binaryReader)
{
int maxMagicBytesLength = _ImageFormatDecoders.Keys.OrderByDescending(x => x.Length).First().Length;
byte[] magicBytes = new byte[maxMagicBytesLength];
for (int i = 0; i < maxMagicBytesLength; i += 1)
{
magicBytes[i] = binaryReader.ReadByte();
foreach (KeyValuePair<byte[], Func<BinaryReader, Size?>> kvPair in _ImageFormatDecoders)
{
if (StartsWith(magicBytes, kvPair.Key))
return kvPair.Value(binaryReader);
}
}
return null;
}
internal static Size? GetDimensions(string path)
{
using BinaryReader binaryReader = new(File.OpenRead(path));
return GetDimensions(binaryReader);
}
}

View File

@ -0,0 +1,529 @@
using MetadataExtractor;
using MetadataExtractor.Formats.Exif;
using MetadataExtractor.Formats.Exif.Makernotes;
using System.Globalization;
using View_by_Distance.Metadata.Models.Stateless.Methods;
namespace View_by_Distance.Metadata.Models.Stateless;
internal abstract class Exif
{
private static DateTime? GetDateTime(string? value)
{
DateTime? result;
string dateTimeFormat = "yyyy:MM:dd HH:mm:ss";
string alternateFormat = "ddd MMM dd HH:mm:ss yyyy";
if (value is not null && DateTime.TryParse(value, out DateTime dateTime))
result = dateTime;
else if (value is not null && value.Length == dateTimeFormat.Length && DateTime.TryParseExact(value, dateTimeFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
result = dateTime;
else if (value is not null && value.Length == alternateFormat.Length && DateTime.TryParseExact(value, alternateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
result = dateTime;
else
result = null;
return result;
}
private static Shared.Models.AviDirectory[] GetAviDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Shared.Models.AviDirectory> results = [];
IEnumerable<MetadataExtractor.Formats.Avi.AviDirectory> aviDirectories = directories.OfType<MetadataExtractor.Formats.Avi.AviDirectory>();
foreach (MetadataExtractor.Formats.Avi.AviDirectory aviDirectory in aviDirectories)
{
if (aviDirectory.Tags.Count == 0)
continue;
DateTime? dateTimeOriginal;
string? duration = aviDirectory.GetDescription(MetadataExtractor.Formats.Avi.AviDirectory.TagDuration);
string? height = aviDirectory.GetDescription(MetadataExtractor.Formats.Avi.AviDirectory.TagHeight);
string? width = aviDirectory.GetDescription(MetadataExtractor.Formats.Avi.AviDirectory.TagWidth);
if (aviDirectory.TryGetDateTime(MetadataExtractor.Formats.Avi.AviDirectory.TagDateTimeOriginal, out DateTime checkDateTime))
dateTimeOriginal = checkDateTime;
else
dateTimeOriginal = GetDateTime(aviDirectory.GetString(MetadataExtractor.Formats.Avi.AviDirectory.TagDateTimeOriginal));
if (dateTimeOriginal is null && duration is null && height is null && width is null)
continue;
results.Add(new(dateTimeOriginal, duration, height, width));
}
return results.ToArray();
}
private static Shared.Models.ExifDirectoryBase[] GetExifBaseDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Shared.Models.ExifDirectoryBase> results = [];
IEnumerable<ExifDirectoryBase> exifBaseDirectories = directories.OfType<ExifDirectoryBase>();
foreach (ExifDirectoryBase exifDirectoryBase in exifBaseDirectories)
{
if (exifDirectoryBase.Tags.Count == 0)
continue;
DateTime? dateTime;
DateTime checkDateTime;
DateTime? dateTimeOriginal;
DateTime? dateTimeDigitized;
string? aperture = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagAperture);
string? applicationNotes = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagApplicationNotes);
string? artist = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagArtist);
string? bitsPerSample = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagBitsPerSample);
string? bodySerialNumber = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagBodySerialNumber);
string? cameraOwnerName = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagCameraOwnerName);
string? compressedAverageBitsPerPixel = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagCompressedAverageBitsPerPixel);
string? compression = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagCompression);
string? copyright = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagCopyright);
string? documentName = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagDocumentName);
string? exifVersion = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagExifVersion);
string? exposureTime = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagExposureTime);
string? fileSource = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagFileSource);
string? imageDescription = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagImageDescription);
string? imageHeight = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagImageHeight);
string? imageNumber = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagImageNumber);
string? imageUniqueId = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagImageUniqueId);
string? imageWidth = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagImageWidth);
string? isoSpeed = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagIsoSpeed);
string? lensMake = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagLensMake);
string? lensModel = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagLensModel);
string? lensSerialNumber = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagLensSerialNumber);
string? make = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagMake);
string? makerNote = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagMakernote);
string? model = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagModel);
string? orientation = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagOrientation);
int? orientationValue = orientation is null ? null : exifDirectoryBase.GetInt32(ExifDirectoryBase.TagOrientation);
string? rating = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagRating);
string? ratingPercent = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagRatingPercent);
string? securityClassification = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagSecurityClassification);
string? shutterSpeed = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagShutterSpeed);
string? software = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagSoftware);
string? timeZone = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagTimeZone);
string? timeZoneDigitized = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagTimeZoneDigitized);
string? timeZoneOriginal = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagTimeZoneOriginal);
string? userComment = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagUserComment);
string? winAuthor = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagWinAuthor);
string? winComment = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagWinComment);
string? winKeywords = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagWinKeywords);
string? winSubject = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagWinSubject);
string? winTitle = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagWinTitle);
string? xResolution = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagXResolution);
string? yResolution = exifDirectoryBase.GetDescription(ExifDirectoryBase.TagYResolution);
if (exifDirectoryBase.TryGetDateTime(ExifDirectoryBase.TagDateTime, out checkDateTime))
dateTime = checkDateTime;
else
dateTime = GetDateTime(exifDirectoryBase.GetString(ExifDirectoryBase.TagDateTime));
if (exifDirectoryBase.TryGetDateTime(ExifDirectoryBase.TagDateTimeOriginal, out checkDateTime))
dateTimeOriginal = checkDateTime;
else
dateTimeOriginal = GetDateTime(exifDirectoryBase.GetString(ExifDirectoryBase.TagDateTimeOriginal));
if (exifDirectoryBase.TryGetDateTime(ExifDirectoryBase.TagDateTimeDigitized, out checkDateTime))
dateTimeDigitized = checkDateTime;
else
dateTimeDigitized = GetDateTime(exifDirectoryBase.GetString(ExifDirectoryBase.TagDateTimeDigitized));
if (userComment is not null && userComment.Length > 255)
userComment = "...";
if (aperture is null
&& applicationNotes is null
&& artist is null
&& bitsPerSample is null
&& bodySerialNumber is null
&& cameraOwnerName is null
&& compressedAverageBitsPerPixel is null
&& compression is null
&& copyright is null
&& dateTime is null
&& dateTimeDigitized is null
&& dateTimeOriginal is null
&& documentName is null
&& exifVersion is null
&& exposureTime is null
&& fileSource is null
&& imageDescription is null
&& imageHeight is null
&& imageNumber is null
&& imageUniqueId is null
&& imageWidth is null
&& isoSpeed is null
&& lensMake is null
&& lensModel is null
&& lensSerialNumber is null
&& make is null
&& makerNote is null
&& model is null
&& orientation is null
&& orientationValue is null
&& rating is null
&& ratingPercent is null
&& securityClassification is null
&& shutterSpeed is null
&& software is null
&& timeZone is null
&& timeZoneDigitized is null
&& timeZoneOriginal is null
&& userComment is null
&& winAuthor is null
&& winComment is null
&& winKeywords is null
&& winSubject is null
&& winTitle is null
&& xResolution is not null
&& yResolution is null)
continue;
results.Add(new(aperture,
applicationNotes,
artist,
bitsPerSample,
bodySerialNumber,
cameraOwnerName,
compressedAverageBitsPerPixel,
compression,
copyright,
dateTime,
dateTimeDigitized,
dateTimeOriginal,
documentName,
exifVersion,
exposureTime,
fileSource,
imageDescription,
imageHeight,
imageNumber,
imageUniqueId,
imageWidth,
isoSpeed,
lensMake,
lensModel,
lensSerialNumber,
make,
makerNote,
model,
orientation,
orientationValue,
rating,
ratingPercent,
securityClassification,
shutterSpeed,
software,
timeZone,
timeZoneDigitized,
timeZoneOriginal,
userComment,
winAuthor,
winComment,
winKeywords,
winSubject,
winTitle,
xResolution,
yResolution));
}
return results.ToArray();
}
private static Shared.Models.FileMetadataDirectory[] GetFileMetadataDirectories(string file, IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Shared.Models.FileMetadataDirectory> results = [];
IEnumerable<MetadataExtractor.Formats.FileSystem.FileMetadataDirectory> fileMetadataDirectories = directories.OfType<MetadataExtractor.Formats.FileSystem.FileMetadataDirectory>();
foreach (MetadataExtractor.Formats.FileSystem.FileMetadataDirectory fileMetadataDirectory in fileMetadataDirectories)
{
if (fileMetadataDirectory.Tags.Count == 0)
continue;
DateTime? fileModifiedDate;
string? fileName = fileMetadataDirectory.GetDescription(MetadataExtractor.Formats.FileSystem.FileMetadataDirectory.TagFileName);
string? fileSize = fileMetadataDirectory.GetDescription(MetadataExtractor.Formats.FileSystem.FileMetadataDirectory.TagFileSize);
if (fileMetadataDirectory.TryGetDateTime(MetadataExtractor.Formats.FileSystem.FileMetadataDirectory.TagFileModifiedDate, out DateTime checkDateTime))
fileModifiedDate = checkDateTime;
else
fileModifiedDate = GetDateTime(fileMetadataDirectory.GetString(MetadataExtractor.Formats.FileSystem.FileMetadataDirectory.TagFileModifiedDate));
if (fileName is null || !file.EndsWith(fileName))
throw new NotSupportedException($"!{file}.EndsWith({fileName})");
if (fileModifiedDate is null && fileName is null && fileSize is null)
continue;
results.Add(new(fileModifiedDate, fileName, fileSize));
}
return results.ToArray();
}
private static Shared.Models.GifHeaderDirectory[] GetGifHeaderDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Shared.Models.GifHeaderDirectory> results = [];
IEnumerable<MetadataExtractor.Formats.Gif.GifHeaderDirectory> gifHeaderDirectories = directories.OfType<MetadataExtractor.Formats.Gif.GifHeaderDirectory>();
foreach (MetadataExtractor.Formats.Gif.GifHeaderDirectory gifHeaderDirectory in gifHeaderDirectories)
{
if (gifHeaderDirectory.Tags.Count == 0)
continue;
string? imageHeight = gifHeaderDirectory.GetDescription(MetadataExtractor.Formats.Gif.GifHeaderDirectory.TagImageHeight);
string? imageWidth = gifHeaderDirectory.GetDescription(MetadataExtractor.Formats.Gif.GifHeaderDirectory.TagImageWidth);
if (imageHeight is null && imageWidth is null)
continue;
results.Add(new(imageHeight, imageWidth));
}
return results.ToArray();
}
private static Shared.Models.GpsDirectory[] GetGpsDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Shared.Models.GpsDirectory> results = [];
IEnumerable<GpsDirectory> gpsDirectories = directories.OfType<GpsDirectory>();
foreach (GpsDirectory gpsDirectory in gpsDirectories)
{
if (gpsDirectory.Tags.Count == 0)
continue;
DateTime? timeStamp;
string? altitude = gpsDirectory.GetDescription(GpsDirectory.TagAltitude);
string? latitude = gpsDirectory.GetDescription(GpsDirectory.TagLatitude);
string? latitudeRef = gpsDirectory.GetDescription(GpsDirectory.TagLatitudeRef);
string? longitude = gpsDirectory.GetDescription(GpsDirectory.TagLongitude);
string? longitudeRef = gpsDirectory.GetDescription(GpsDirectory.TagLongitudeRef);
if (gpsDirectory.TryGetDateTime(GpsDirectory.TagTimeStamp, out DateTime checkDateTime))
timeStamp = checkDateTime;
else
timeStamp = GetDateTime(gpsDirectory.GetString(GpsDirectory.TagTimeStamp));
if (altitude is null && latitude is null && latitudeRef is null && longitude is null && longitudeRef is null && timeStamp is null)
continue;
results.Add(new(altitude,
latitude,
latitudeRef,
longitude,
longitudeRef,
timeStamp));
}
return results.ToArray();
}
private static Shared.Models.JpegDirectory[] GetJpegDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Shared.Models.JpegDirectory> results = [];
IEnumerable<MetadataExtractor.Formats.Jpeg.JpegDirectory> jpegDirectories = directories.OfType<MetadataExtractor.Formats.Jpeg.JpegDirectory>();
foreach (MetadataExtractor.Formats.Jpeg.JpegDirectory jpegDirectory in jpegDirectories)
{
if (jpegDirectory.Tags.Count == 0)
continue;
string? imageHeight = jpegDirectory.GetDescription(MetadataExtractor.Formats.Jpeg.JpegDirectory.TagImageHeight);
string? imageWidth = jpegDirectory.GetDescription(MetadataExtractor.Formats.Jpeg.JpegDirectory.TagImageWidth);
if (imageHeight is null && imageWidth is null)
continue;
results.Add(new(imageHeight, imageWidth));
}
return results.ToArray();
}
private static Shared.Models.MakernoteDirectory[] GetMakernoteDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Shared.Models.MakernoteDirectory> results = [];
IEnumerable<AppleMakernoteDirectory> appleMakernoteDirectories = directories.OfType<AppleMakernoteDirectory>();
foreach (AppleMakernoteDirectory appleMakernoteDirectory in appleMakernoteDirectories)
{
if (appleMakernoteDirectory.Tags.Count == 0)
continue;
string? cameraSerialNumber = null;
string? firmwareVersion = null;
string? qualityAndFileFormat = null;
if (cameraSerialNumber is null && firmwareVersion is null && qualityAndFileFormat is null)
continue;
results.Add(new(cameraSerialNumber, firmwareVersion, qualityAndFileFormat));
}
IEnumerable<CanonMakernoteDirectory> canonMakernoteDirectories = directories.OfType<CanonMakernoteDirectory>();
foreach (CanonMakernoteDirectory canonMakernoteDirectory in canonMakernoteDirectories)
{
if (canonMakernoteDirectory.Tags.Count == 0)
continue;
string? cameraSerialNumber = canonMakernoteDirectory.GetDescription(CanonMakernoteDirectory.TagModelId);
string? firmwareVersion = canonMakernoteDirectory.GetDescription(CanonMakernoteDirectory.TagCanonFirmwareVersion);
string? qualityAndFileFormat = canonMakernoteDirectory.GetDescription(CanonMakernoteDirectory.CameraSettings.TagQuality);
if (cameraSerialNumber is null && firmwareVersion is null && qualityAndFileFormat is null)
continue;
results.Add(new(cameraSerialNumber, firmwareVersion, qualityAndFileFormat));
}
IEnumerable<NikonType2MakernoteDirectory> nikonType2MakernoteDirectories = directories.OfType<NikonType2MakernoteDirectory>();
foreach (NikonType2MakernoteDirectory nikonType2MakernoteDirectory in nikonType2MakernoteDirectories)
{
if (nikonType2MakernoteDirectory.Tags.Count == 0)
continue;
string? cameraSerialNumber = nikonType2MakernoteDirectory.GetDescription(NikonType2MakernoteDirectory.TagCameraSerialNumber);
string? firmwareVersion = nikonType2MakernoteDirectory.GetDescription(NikonType2MakernoteDirectory.TagFirmwareVersion);
string? qualityAndFileFormat = nikonType2MakernoteDirectory.GetDescription(NikonType2MakernoteDirectory.TagQualityAndFileFormat);
if (cameraSerialNumber is null && firmwareVersion is null && qualityAndFileFormat is null)
continue;
results.Add(new(cameraSerialNumber, firmwareVersion, qualityAndFileFormat));
}
IEnumerable<OlympusMakernoteDirectory> olympusMakernoteDirectories = directories.OfType<OlympusMakernoteDirectory>();
foreach (OlympusMakernoteDirectory olympusMakernoteDirectory in olympusMakernoteDirectories)
{
if (olympusMakernoteDirectory.Tags.Count == 0)
continue;
string? cameraSerialNumber = olympusMakernoteDirectory.GetDescription(OlympusMakernoteDirectory.TagSerialNumber1);
string? firmwareVersion = olympusMakernoteDirectory.GetDescription(OlympusMakernoteDirectory.TagBodyFirmwareVersion);
string? qualityAndFileFormat = olympusMakernoteDirectory.GetDescription(OlympusMakernoteDirectory.TagJpegQuality);
if (cameraSerialNumber is null && firmwareVersion is null && qualityAndFileFormat is null)
continue;
results.Add(new(cameraSerialNumber, firmwareVersion, qualityAndFileFormat));
}
IEnumerable<PanasonicMakernoteDirectory> panasonicMakernoteDirectories = directories.OfType<PanasonicMakernoteDirectory>();
foreach (PanasonicMakernoteDirectory panasonicMakernoteDirectory in panasonicMakernoteDirectories)
{
if (panasonicMakernoteDirectory.Tags.Count == 0)
continue;
string? cameraSerialNumber = panasonicMakernoteDirectory.GetDescription(PanasonicMakernoteDirectory.TagInternalSerialNumber);
string? firmwareVersion = panasonicMakernoteDirectory.GetDescription(PanasonicMakernoteDirectory.TagFirmwareVersion);
string? qualityAndFileFormat = panasonicMakernoteDirectory.GetDescription(PanasonicMakernoteDirectory.TagQualityMode);
if (cameraSerialNumber is null && firmwareVersion is null && qualityAndFileFormat is null)
continue;
results.Add(new(cameraSerialNumber, firmwareVersion, qualityAndFileFormat));
}
IEnumerable<SamsungType2MakernoteDirectory> samsungType2MakernoteDirectories = directories.OfType<SamsungType2MakernoteDirectory>();
foreach (SamsungType2MakernoteDirectory samsungType2MakernoteDirectory in samsungType2MakernoteDirectories)
{
if (samsungType2MakernoteDirectory.Tags.Count == 0)
continue;
string? cameraSerialNumber = samsungType2MakernoteDirectory.GetDescription(SamsungType2MakernoteDirectory.TagSerialNumber);
string? firmwareVersion = samsungType2MakernoteDirectory.GetDescription(SamsungType2MakernoteDirectory.TagFirmwareName);
string? qualityAndFileFormat = null;
if (cameraSerialNumber is null && firmwareVersion is null && qualityAndFileFormat is null)
continue;
results.Add(new(cameraSerialNumber, firmwareVersion, qualityAndFileFormat));
}
IEnumerable<SonyType6MakernoteDirectory> sonyType6MakernoteDirectories = directories.OfType<SonyType6MakernoteDirectory>();
foreach (SonyType6MakernoteDirectory sonyType6MakernoteDirectory in sonyType6MakernoteDirectories)
{
if (sonyType6MakernoteDirectory.Tags.Count == 0)
continue;
string? cameraSerialNumber = null;
string? firmwareVersion = null;
string? qualityAndFileFormat = null;
if (cameraSerialNumber is null && firmwareVersion is null && qualityAndFileFormat is null)
continue;
results.Add(new(cameraSerialNumber, firmwareVersion, qualityAndFileFormat));
}
return results.ToArray();
}
private static Shared.Models.PhotoshopDirectory[] GetPhotoshopDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Shared.Models.PhotoshopDirectory> results = [];
IEnumerable<MetadataExtractor.Formats.Photoshop.PhotoshopDirectory> photoshopDirectories = directories.OfType<MetadataExtractor.Formats.Photoshop.PhotoshopDirectory>();
foreach (MetadataExtractor.Formats.Photoshop.PhotoshopDirectory photoshopDirectory in photoshopDirectories)
{
if (photoshopDirectory.Tags.Count == 0)
continue;
string? jpegQuality = photoshopDirectory.GetDescription(MetadataExtractor.Formats.Photoshop.PhotoshopDirectory.TagJpegQuality);
string? url = photoshopDirectory.GetDescription(MetadataExtractor.Formats.Photoshop.PhotoshopDirectory.TagUrl);
if (jpegQuality is null && url is null)
continue;
results.Add(new(jpegQuality, url));
}
return results.ToArray();
}
private static Shared.Models.PngDirectory[] GetPngDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Shared.Models.PngDirectory> results = [];
IEnumerable<MetadataExtractor.Formats.Png.PngDirectory> pngDirectories = directories.OfType<MetadataExtractor.Formats.Png.PngDirectory>();
foreach (MetadataExtractor.Formats.Png.PngDirectory pngDirectory in pngDirectories)
{
if (pngDirectory.Tags.Count == 0)
continue;
string? imageHeight = pngDirectory.GetDescription(MetadataExtractor.Formats.Png.PngDirectory.TagImageHeight);
string? imageWidth = pngDirectory.GetDescription(MetadataExtractor.Formats.Png.PngDirectory.TagImageWidth);
string? textualData = pngDirectory.GetDescription(MetadataExtractor.Formats.Png.PngDirectory.TagTextualData);
if (imageHeight is null && imageWidth is null && textualData is null)
continue;
results.Add(new(imageHeight, imageWidth, textualData));
}
return results.ToArray();
}
private static Shared.Models.QuickTimeMovieHeaderDirectory[] GetQuickTimeMovieHeaderDirectoryDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Shared.Models.QuickTimeMovieHeaderDirectory> results = [];
IEnumerable<MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory> quickTimeMovieHeaderDirectories = directories.OfType<MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory>();
foreach (MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory quickTimeMovieHeaderDirectory in quickTimeMovieHeaderDirectories)
{
if (quickTimeMovieHeaderDirectory.Tags.Count == 0)
continue;
DateTime? created;
if (quickTimeMovieHeaderDirectory.TryGetDateTime(MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory.TagCreated, out DateTime checkDateTime))
created = checkDateTime;
else
created = GetDateTime(quickTimeMovieHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeMovieHeaderDirectory.TagCreated));
if (created is null)
continue;
results.Add(new(created));
}
return results.ToArray();
}
private static Shared.Models.QuickTimeTrackHeaderDirectory[] GetQuickTimeTrackHeaderDirectoryDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Shared.Models.QuickTimeTrackHeaderDirectory> results = [];
IEnumerable<MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory> quickTimeTrackHeaderDirectories = directories.OfType<MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory>();
foreach (MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory quickTimeTrackHeaderDirectory in quickTimeTrackHeaderDirectories)
{
if (quickTimeTrackHeaderDirectory.Tags.Count == 0)
continue;
DateTime? created;
if (quickTimeTrackHeaderDirectory.TryGetDateTime(MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory.TagCreated, out DateTime checkDateTime))
created = checkDateTime;
else
created = GetDateTime(quickTimeTrackHeaderDirectory.GetString(MetadataExtractor.Formats.QuickTime.QuickTimeTrackHeaderDirectory.TagCreated));
if (created is null)
continue;
results.Add(new(created));
}
return results.ToArray();
}
private static Shared.Models.WebPDirectory[] GetWebPDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Shared.Models.WebPDirectory> results = [];
IEnumerable<MetadataExtractor.Formats.WebP.WebPDirectory> webPDirectories = directories.OfType<MetadataExtractor.Formats.WebP.WebPDirectory>();
foreach (MetadataExtractor.Formats.WebP.WebPDirectory webPDirectory in webPDirectories)
{
if (webPDirectory.Tags.Count == 0)
continue;
string? imageHeight = webPDirectory.GetDescription(MetadataExtractor.Formats.WebP.WebPDirectory.TagImageHeight);
string? imageWidth = webPDirectory.GetDescription(MetadataExtractor.Formats.WebP.WebPDirectory.TagImageWidth);
if (imageHeight is null && imageWidth is null)
continue;
results.Add(new(imageHeight, imageWidth));
}
return results.ToArray();
}
private static Shared.Models.ExifDirectory Covert(Shared.Models.FilePath filePath, System.Drawing.Size? size, IReadOnlyList<MetadataExtractor.Directory> directories)
{
Shared.Models.ExifDirectory result;
Shared.Models.AviDirectory[] aviDirectories = GetAviDirectories(directories);
Shared.Models.GpsDirectory[] gpsDirectories = GetGpsDirectories(directories);
Shared.Models.PngDirectory[] pngDirectories = GetPngDirectories(directories);
Shared.Models.JpegDirectory[] jpegDirectories = GetJpegDirectories(directories);
Shared.Models.WebPDirectory[] webPDirectories = GetWebPDirectories(directories);
Shared.Models.ExifDirectoryBase[] exifBaseDirectories = GetExifBaseDirectories(directories);
Shared.Models.GifHeaderDirectory[] gifHeaderDirectories = GetGifHeaderDirectories(directories);
Shared.Models.MakernoteDirectory[] makernoteDirectories = GetMakernoteDirectories(directories);
Shared.Models.PhotoshopDirectory[] photoshopDirectories = GetPhotoshopDirectories(directories);
Shared.Models.FileMetadataDirectory[] fileMetadataDirectories = GetFileMetadataDirectories(filePath.FullName, directories);
Shared.Models.QuickTimeMovieHeaderDirectory[] quickTimeMovieHeaderDirectories = GetQuickTimeMovieHeaderDirectoryDirectories(directories);
Shared.Models.QuickTimeTrackHeaderDirectory[] quickTimeTrackHeaderDirectories = GetQuickTimeTrackHeaderDirectoryDirectories(directories);
result = new(aviDirectories,
exifBaseDirectories,
fileMetadataDirectories,
gifHeaderDirectories,
gpsDirectories,
size?.Height,
jpegDirectories,
makernoteDirectories,
filePath.Name,
photoshopDirectories,
pngDirectories,
quickTimeMovieHeaderDirectories,
quickTimeTrackHeaderDirectories,
webPDirectories,
size?.Width);
return result;
}
internal static Shared.Models.ExifDirectory GetExifDirectory(Shared.Models.FilePath filePath)
{
Shared.Models.ExifDirectory? result;
System.Drawing.Size? size = Dimensions.GetDimensions(filePath.FullName);
IReadOnlyList<MetadataExtractor.Directory> directories = ImageMetadataReader.ReadMetadata(filePath.FullName);
result = Covert(filePath, size, directories);
return result;
}
}

View File

@ -0,0 +1,42 @@
using View_by_Distance.Shared.Models;
namespace View_by_Distance.Metadata.Models.Stateless.Methods;
internal static class Face
{
internal static string? GetFaceEncoding(PngDirectory[]? pngDirectories)
{
string? result = null;
if (pngDirectories is not null)
{
const string comment = "Comment:";
foreach (PngDirectory pngDirectory in pngDirectories)
{
if (pngDirectory.TextualData is null || !pngDirectory.TextualData.StartsWith(comment))
continue;
result = pngDirectory.TextualData[comment.Length..];
break;
}
}
return result;
}
internal static string? GetOutputResolution(PngDirectory[]? pngDirectories)
{
string? result = null;
if (pngDirectories is not null)
{
const string artist = "Artist:";
foreach (PngDirectory pngDirectory in pngDirectories)
{
if (pngDirectory.TextualData is null || !pngDirectory.TextualData.StartsWith(artist))
continue;
result = pngDirectory.TextualData[artist.Length..];
break;
}
}
return result;
}
}

View File

@ -0,0 +1,121 @@
using MetadataExtractor;
using View_by_Distance.Metadata.Models.Stateless.Methods;
using View_by_Distance.Shared.Models;
namespace View_by_Distance.Metadata.Models.Stateless;
internal abstract class GPS
{
private static bool CoordinateValidatorValidate(double latitude, double longitude)
{
if (latitude is < (-90) or > 90)
return false;
if (longitude is < (-180) or > 180)
return false;
return true;
}
private static double GetRadius(IMetadata.DistanceUnit distanceUnit)
{
return distanceUnit switch
{
IMetadata.DistanceUnit.Kilometers => 6371.0, // EarthRadiusInKilometers;
IMetadata.DistanceUnit.Meters => 6371000.0, // EarthRadiusInMeters;
IMetadata.DistanceUnit.NauticalMiles => 3440.0, // EarthRadiusInNauticalMiles;
IMetadata.DistanceUnit.Miles => 3959.0, // EarthRadiusInMiles;
_ => throw new NotSupportedException()
};
}
private static double ToRadian(double d) =>
d * (Math.PI / 180);
private static double DiffRadian(double val1, double val2) =>
ToRadian(val2) - ToRadian(val1);
internal static double GetDistance(double originLatitude, double originLongitude, double destinationLatitude, double destinationLongitude, int decimalPlaces = 1, IMetadata.DistanceUnit distanceUnit = IMetadata.DistanceUnit.Miles)
{
if (!CoordinateValidatorValidate(originLatitude, originLongitude))
throw new ArgumentException("Invalid origin coordinates supplied.");
if (!CoordinateValidatorValidate(destinationLatitude, destinationLongitude))
throw new ArgumentException("Invalid destination coordinates supplied.");
double radius = GetRadius(distanceUnit);
return Math.Round(
radius * 2 *
Math.Asin(Math.Min(1,
Math.Sqrt(
Math.Pow(Math.Sin(DiffRadian(originLatitude, destinationLatitude) / 2.0), 2.0) +
Math.Cos(ToRadian(originLatitude)) * Math.Cos(ToRadian(destinationLatitude)) *
Math.Pow(Math.Sin(DiffRadian(originLongitude, destinationLongitude) / 2.0),
2.0)))), decimalPlaces);
}
private static double ParseValueFromDmsString(string value)
{
double result;
if (string.IsNullOrEmpty(value))
return double.MinValue;
double secondsValue;
string[] degrees = value.Split('°');
if (degrees.Length != 2)
return double.MinValue;
if (!double.TryParse(degrees[0], out double degreesValue))
return double.MinValue;
string[] minutes = degrees[1].Split('\'');
if (minutes.Length != 2)
return double.MinValue;
if (!double.TryParse(minutes[0], out double minutesValue))
return double.MinValue;
string[] seconds = minutes[1].Split('"');
if (seconds.Length != 2)
secondsValue = 0;
else
{
if (!double.TryParse(seconds[0], out secondsValue))
return double.MinValue;
}
result = Math.Abs(degreesValue) + (minutesValue / 60) + (secondsValue / 3600);
if (degreesValue < 0)
result *= -1;
return result;
}
internal static GeoLocation? GeoLocation(GpsDirectory[]? gpsDirectories)
{
GeoLocation? result = null;
if (gpsDirectories is not null)
{
foreach (GpsDirectory gpsDirectory in gpsDirectories)
{
if (string.IsNullOrEmpty(gpsDirectory?.Latitude))
result = null;
else
{
string latitudeDMS = gpsDirectory.Latitude;
double latitude = ParseValueFromDmsString(latitudeDMS);
if (string.IsNullOrEmpty(gpsDirectory.Longitude))
result = null;
else
{
string longitudeDMS = gpsDirectory.Longitude;
double longitude = ParseValueFromDmsString(longitudeDMS);
result = new(latitude, longitude);
string dms = result.ToDmsString();
if ($"{latitudeDMS}, {longitudeDMS}" != dms)
result = null;
}
}
if (result is not null)
break;
}
}
return result;
}
}

View File

@ -1,5 +1,5 @@
using MetadataExtractor;
using System.Collections.ObjectModel;
using View_by_Distance.Shared.Models;
namespace View_by_Distance.Metadata.Models.Stateless.Methods;
@ -14,39 +14,54 @@ public interface IMetadata
Meters
}
ReadOnlyDictionary<string, MetadataExtractorDirectory> TestStatic_GetKeyValuePairs(IReadOnlyList<MetadataExtractor.Directory> directories) =>
GetKeyValuePairs(directories);
static ReadOnlyDictionary<string, MetadataExtractorDirectory> GetKeyValuePairs(IReadOnlyList<MetadataExtractor.Directory> directories) =>
new(Metadata.GetKeyValuePairs(directories));
ExifDirectory TestStatic_GetExifDirectory(FilePath filePath) =>
GetExifDirectory(filePath);
static ExifDirectory GetExifDirectory(FilePath filePath) =>
Exif.GetExifDirectory(filePath);
string? TestStatic_GetModel(IReadOnlyList<MetadataExtractor.Directory> directories) =>
GetModel(directories);
static string? GetModel(IReadOnlyList<MetadataExtractor.Directory> directories) =>
Metadata.GetModel(directories);
string TestStatic_GetMaker(ExifDirectory? exifDirectory) =>
GetMaker(exifDirectory);
static string GetMaker(ExifDirectory? exifDirectory) =>
Base.GetMaker(exifDirectory?.ExifBaseDirectories);
string? TestStatic_GetFaceEncoding(IReadOnlyList<MetadataExtractor.Directory> directories) =>
GetFaceEncoding(directories);
static string? GetFaceEncoding(IReadOnlyList<MetadataExtractor.Directory> directories) =>
Metadata.GetFaceEncoding(directories);
string TestStatic_GetModel(ExifDirectory? exifDirectory) =>
GetModel(exifDirectory);
static string GetModel(ExifDirectory? exifDirectory) =>
Base.GetModel(exifDirectory?.ExifBaseDirectories);
string? TestStatic_GetOutputResolution(IReadOnlyList<MetadataExtractor.Directory> directories) =>
GetOutputResolution(directories);
static string? GetOutputResolution(IReadOnlyList<MetadataExtractor.Directory> directories) =>
Metadata.GetOutputResolution(directories);
string? TestStatic_GetOutputResolution(ExifDirectory? exifDirectory) =>
GetOutputResolution(exifDirectory);
static string? GetOutputResolution(ExifDirectory? exifDirectory) =>
Face.GetOutputResolution(exifDirectory?.PngDirectories);
GeoLocation? TestStatic_GeoLocation(IReadOnlyList<MetadataExtractor.Directory> directories) =>
GeoLocation(directories);
static GeoLocation? GeoLocation(IReadOnlyList<MetadataExtractor.Directory> directories) =>
Metadata.GeoLocation(directories);
string? TestStatic_GetFaceEncoding(ExifDirectory? exifDirectory) =>
GetFaceEncoding(exifDirectory);
static string? GetFaceEncoding(ExifDirectory? exifDirectory) =>
Face.GetFaceEncoding(exifDirectory?.PngDirectories);
GeoLocation? TestStatic_GeoLocation(ReadOnlyDictionary<string, MetadataExtractorDirectory> metadataExtractorDirectories) =>
GeoLocation(metadataExtractorDirectories);
static GeoLocation? GeoLocation(ReadOnlyDictionary<string, MetadataExtractorDirectory> metadataExtractorDirectories) =>
Metadata.GeoLocation(metadataExtractorDirectories);
GeoLocation? TestStatic_GeoLocation(ExifDirectory? exifDirectory) =>
GeoLocation(exifDirectory);
static GeoLocation? GeoLocation(ExifDirectory? exifDirectory) =>
GPS.GeoLocation(exifDirectory?.GpsDirectories);
double? TestStatic_GetDistance(double originLatitude, double originLongitude, double destinationLatitude, double destinationLongitude, int decimalPlaces = 1, DistanceUnit distanceUnit = DistanceUnit.Miles) =>
GetDistance(originLatitude, originLongitude, destinationLatitude, destinationLongitude, decimalPlaces, distanceUnit);
static double? GetDistance(double originLatitude, double originLongitude, double destinationLatitude, double destinationLongitude, int decimalPlaces = 1, DistanceUnit distanceUnit = DistanceUnit.Miles) =>
Metadata.GetDistance(originLatitude, originLongitude, destinationLatitude, destinationLongitude, decimalPlaces, distanceUnit);
GPS.GetDistance(originLatitude, originLongitude, destinationLatitude, destinationLongitude, decimalPlaces, distanceUnit);
// string? TestStatic_GetFaceEncoding(IReadOnlyList<MetadataExtractor.Directory> directories) =>
// GetFaceEncoding(directories);
// static string? GetFaceEncoding(IReadOnlyList<MetadataExtractor.Directory> directories) =>
// Metadata.GetFaceEncoding(directories);
// string? TestStatic_GetOutputResolution(IReadOnlyList<MetadataExtractor.Directory> directories) =>
// GetOutputResolution(directories);
// static string? GetOutputResolution(IReadOnlyList<MetadataExtractor.Directory> directories) =>
// Metadata.GetOutputResolution(directories);
// Dictionary<string, MetadataExtractorDirectory> TestStatic_GetMetadataCollection(FileInfo fileInfo, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions) =>
// GetMetadataCollection(fileInfo, subFileTuples, parseExceptions);
// static Dictionary<string, MetadataExtractorDirectory> GetMetadataCollection(FileInfo fileInfo, List<Tuple<string, DateTime>> subFileTuples, List<string> parseExceptions) =>
// Metadata.GetMetadataCollection(fileInfo, subFileTuples, parseExceptions);
}

View File

@ -1,229 +0,0 @@
using MetadataExtractor;
using MetadataExtractor.Formats.Exif;
using System.Collections.ObjectModel;
using System.Text.Json;
using static View_by_Distance.Metadata.Models.Stateless.Methods.IMetadata;
namespace View_by_Distance.Metadata.Models.Stateless.Methods;
internal partial class Metadata
{
internal static Dictionary<string, MetadataExtractorDirectory> GetKeyValuePairs(IReadOnlyList<MetadataExtractor.Directory> directories)
{
Dictionary<string, MetadataExtractorDirectory> results = [];
MetadataExtractorTag metadataExtractorTag;
MetadataExtractorDirectory? metadataExtractorDirectory;
Dictionary<int, MetadataExtractorTag> metadataExtractorTags;
foreach (MetadataExtractor.Directory directory in directories)
{
metadataExtractorTags = [];
if (results.TryGetValue(directory.Name, out metadataExtractorDirectory))
continue;
foreach (Tag tag in directory.Tags)
{
metadataExtractorTag = new(tag.Type, tag.Description, tag.HasName, tag.Name);
metadataExtractorTags.Add(tag.Type, metadataExtractorTag);
}
metadataExtractorDirectory = new(directory.Name, directory.HasError, new(directory.Errors.ToArray()), new(metadataExtractorTags));
results.Add(directory.Name, metadataExtractorDirectory);
}
return results;
}
internal static Dictionary<string, MetadataExtractorDirectory> Deserialize(string json)
{
Dictionary<string, MetadataExtractorDirectory> results = [];
Record? record;
MetadataExtractorDirectory metadataExtractorDirectory;
Dictionary<string, JsonElement>? keyValuePairs = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(json);
if (keyValuePairs is null)
throw new NullReferenceException(nameof(keyValuePairs));
foreach (KeyValuePair<string, JsonElement> keyValuePair in keyValuePairs)
{
record = JsonSerializer.Deserialize(keyValuePair.Value.ToString(), RecordSourceGenerationContext.Default.Record);
if (record is null)
throw new NullReferenceException(nameof(record));
metadataExtractorDirectory = new(record.Name, record.HasError, new(record.Errors), new(record.Tags));
results.Add(record.Name, metadataExtractorDirectory);
}
return results;
}
internal static string? GetFaceEncoding(IReadOnlyList<MetadataExtractor.Directory> directories)
{
string? result;
List<string> results = [];
const string comment = "Comment: ";
foreach (MetadataExtractor.Directory directory in directories)
{
if (directory.Name != "PNG-tEXt")
continue;
foreach (Tag tag in directory.Tags)
{
if (tag.Name != "Textual Data" || string.IsNullOrEmpty(tag.Description))
continue;
if (!tag.Description.StartsWith(comment))
continue;
results.Add(tag.Description);
}
}
result = results.Count != 0 ? results[0][comment.Length..] : null;
return result;
}
internal static string? GetOutputResolution(IReadOnlyList<MetadataExtractor.Directory> directories)
{
string? result;
List<string> results = [];
const string artist = "Artist: ";
foreach (MetadataExtractor.Directory directory in directories)
{
if (directory.Name != "PNG-tEXt")
continue;
foreach (Tag tag in directory.Tags)
{
if (tag.Name != "Textual Data" || string.IsNullOrEmpty(tag.Description))
continue;
if (!tag.Description.StartsWith(artist))
continue;
results.Add(tag.Description);
}
}
result = results.Count != 0 ? results[0][artist.Length..] : null;
return result;
}
internal static string? GetModel(IReadOnlyList<MetadataExtractor.Directory> directories)
{
string? result;
ExifDirectoryBase? exifDirectoryBase = directories.OfType<ExifDirectoryBase>().FirstOrDefault();
if (exifDirectoryBase is null)
result = null;
else
result = exifDirectoryBase.GetString(ExifDirectoryBase.TagModel);
return result;
}
internal static GeoLocation? GeoLocation(IReadOnlyList<MetadataExtractor.Directory> directories)
{
GeoLocation? result;
GpsDirectory? gpsDirectory = directories.OfType<GpsDirectory>().FirstOrDefault();
if (gpsDirectory is null)
result = null;
else
result = gpsDirectory.GetGeoLocation();
return result;
}
private static bool CoordinateValidatorValidate(double latitude, double longitude)
{
if (latitude is < (-90) or > 90)
return false;
if (longitude is < (-180) or > 180)
return false;
return true;
}
private static double GetRadius(DistanceUnit distanceUnit)
{
return distanceUnit switch
{
DistanceUnit.Kilometers => 6371.0, // EarthRadiusInKilometers;
DistanceUnit.Meters => 6371000.0, // EarthRadiusInMeters;
DistanceUnit.NauticalMiles => 3440.0, // EarthRadiusInNauticalMiles;
DistanceUnit.Miles => 3959.0, // EarthRadiusInMiles;
_ => throw new NotSupportedException()
};
}
private static double ToRadian(double d) =>
d * (Math.PI / 180);
private static double DiffRadian(double val1, double val2) =>
ToRadian(val2) - ToRadian(val1);
internal static double GetDistance(double originLatitude, double originLongitude, double destinationLatitude, double destinationLongitude, int decimalPlaces = 1, DistanceUnit distanceUnit = DistanceUnit.Miles)
{
if (!CoordinateValidatorValidate(originLatitude, originLongitude))
throw new ArgumentException("Invalid origin coordinates supplied.");
if (!CoordinateValidatorValidate(destinationLatitude, destinationLongitude))
throw new ArgumentException("Invalid destination coordinates supplied.");
double radius = GetRadius(distanceUnit);
return Math.Round(
radius * 2 *
Math.Asin(Math.Min(1,
Math.Sqrt(
Math.Pow(Math.Sin(DiffRadian(originLatitude, destinationLatitude) / 2.0), 2.0) +
Math.Cos(ToRadian(originLatitude)) * Math.Cos(ToRadian(destinationLatitude)) *
Math.Pow(Math.Sin(DiffRadian(originLongitude, destinationLongitude) / 2.0),
2.0)))), decimalPlaces);
}
private static double ParseValueFromDmsString(string value)
{
double result;
if (string.IsNullOrEmpty(value))
return double.MinValue;
double secondsValue;
string[] degrees = value.Split('°');
if (degrees.Length != 2)
return double.MinValue;
if (!double.TryParse(degrees[0], out double degreesValue))
return double.MinValue;
string[] minutes = degrees[1].Split('\'');
if (minutes.Length != 2)
return double.MinValue;
if (!double.TryParse(minutes[0], out double minutesValue))
return double.MinValue;
string[] seconds = minutes[1].Split('"');
if (seconds.Length != 2)
secondsValue = 0;
else
{
if (!double.TryParse(seconds[0], out secondsValue))
return double.MinValue;
}
result = Math.Abs(degreesValue) + (minutesValue / 60) + (secondsValue / 3600);
if (degreesValue < 0)
result *= -1;
return result;
}
internal static GeoLocation? GeoLocation(ReadOnlyDictionary<string, MetadataExtractorDirectory> metadataExtractorDirectories)
{
GeoLocation? result;
if (!metadataExtractorDirectories.TryGetValue("GPS", out MetadataExtractorDirectory? metadataExtractorDirectory))
result = null;
else
{
MetadataExtractorTag? metadataExtractorTag;
if (!metadataExtractorDirectory.Tags.TryGetValue((int)Shared.Models.Stateless.IExif.Tags.GPSLatitude, out metadataExtractorTag) || string.IsNullOrEmpty(metadataExtractorTag.Description))
result = null;
else
{
string latitudeDMS = metadataExtractorTag.Description;
double latitude = ParseValueFromDmsString(latitudeDMS);
if (!metadataExtractorDirectory.Tags.TryGetValue((int)Shared.Models.Stateless.IExif.Tags.GPSLongitude, out metadataExtractorTag) || string.IsNullOrEmpty(metadataExtractorTag.Description))
result = null;
else
{
string longitudeDMS = metadataExtractorTag.Description;
double longitude = ParseValueFromDmsString(longitudeDMS);
result = new(latitude, longitude);
string dms = result.ToDmsString();
if ($"{latitudeDMS}, {longitudeDMS}" != dms)
result = null;
}
}
}
return result;
}
}

View File

@ -10,7 +10,6 @@ using System.Text;
using View_by_Distance.Offset.Date.Time.Original.Models;
using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Methods;
using View_by_Distance.Shared.Models.Stateless;
namespace View_by_Distance.Offset.Date.Time.Original;
@ -113,7 +112,7 @@ public class OffsetDateTimeOriginal
string checkFile;
PropertyItem? propertyItem;
string? ticksDirectory = null;
int dateTimeOriginal = (int)IExif.Tags.DateTimeOriginal;
int dateTimeOriginal = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeOriginal;
for (int i = 0; i < int.MaxValue; i++)
{
ticksDirectory = Path.Combine(sourceDirectory, ticks.ToString());

View File

@ -8,7 +8,6 @@ using System.Text;
using System.Text.RegularExpressions;
using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Methods;
using View_by_Distance.Shared.Models.Stateless;
namespace View_by_Distance.Property.Models.Stateless;
@ -207,13 +206,12 @@ internal partial class Property
DateTime? dateTimeOriginal = null;
DateTime? dateTimeDigitized = null;
DateTime? dateTimeOriginalByLogic = null;
IReadOnlyList<MetadataExtractor.Directory> directories;
DateTime? dateTimeFromName = GetDateTimeFromName(fileHolder);
if (!isValidImageFormatExtension && fileHolder.Exists && metadata is not null)
{
try
{
directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(fileHolder.FullName);
IReadOnlyList<MetadataExtractor.Directory> directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(fileHolder.FullName);
(dateTimeOriginalByLogic, DateTime?[] metadataDateTimes) = metadata.GetDateTimes(fileHolder, directories);
dateTimesByLogic = GetDateTimes(metadataDateTimes);
message = null;
@ -244,9 +242,9 @@ internal partial class Property
id ??= Shared.Models.Stateless.Methods.IId.GetDeterministicHashCode(bytes);
}
dateTimeFormat = IProperty.DateTimeFormat();
if (image.PropertyIdList.Contains((int)IExif.Tags.DateTime))
if (image.PropertyIdList.Contains(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTime))
{
propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTime);
propertyItem = image.GetPropertyItem(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTime);
if (propertyItem?.Value is not null)
{
value = asciiEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1);
@ -256,9 +254,9 @@ internal partial class Property
dateTime = checkDateTime;
}
}
if (image.PropertyIdList.Contains((int)IExif.Tags.DateTimeDigitized))
if (image.PropertyIdList.Contains(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeDigitized))
{
propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTimeDigitized);
propertyItem = image.GetPropertyItem(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeDigitized);
if (propertyItem?.Value is not null)
{
value = asciiEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1);
@ -268,9 +266,9 @@ internal partial class Property
dateTimeDigitized = checkDateTime;
}
}
if (image.PropertyIdList.Contains((int)IExif.Tags.DateTimeOriginal))
if (image.PropertyIdList.Contains(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeOriginal))
{
propertyItem = image.GetPropertyItem((int)IExif.Tags.DateTimeOriginal);
propertyItem = image.GetPropertyItem(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeOriginal);
if (propertyItem?.Value is not null)
{
value = asciiEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1);
@ -280,9 +278,9 @@ internal partial class Property
dateTimeOriginal = checkDateTime;
}
}
if (image.PropertyIdList.Contains((int)IExif.Tags.GPSDateStamp))
if (image.PropertyIdList.Contains(MetadataExtractor.Formats.Exif.GpsDirectory.TagDateStamp))
{
propertyItem = image.GetPropertyItem((int)IExif.Tags.GPSDateStamp);
propertyItem = image.GetPropertyItem(MetadataExtractor.Formats.Exif.GpsDirectory.TagDateStamp);
if (propertyItem?.Value is not null)
{
value = asciiEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1);
@ -292,27 +290,27 @@ internal partial class Property
gpsDateStamp = checkDateTime;
}
}
if (image.PropertyIdList.Contains((int)IExif.Tags.Make))
if (image.PropertyIdList.Contains(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagMake))
{
propertyItem = image.GetPropertyItem((int)IExif.Tags.Make);
propertyItem = image.GetPropertyItem(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagMake);
if (propertyItem?.Value is not null)
make = asciiEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1);
}
if (image.PropertyIdList.Contains((int)IExif.Tags.Model))
if (image.PropertyIdList.Contains(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagModel))
{
propertyItem = image.GetPropertyItem((int)IExif.Tags.Model);
propertyItem = image.GetPropertyItem(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagModel);
if (propertyItem?.Value is not null)
model = asciiEncoding.GetString(propertyItem.Value, 0, propertyItem.Len - 1);
}
if (image.PropertyIdList.Contains((int)IExif.Tags.Orientation))
if (image.PropertyIdList.Contains(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagOrientation))
{
propertyItem = image.GetPropertyItem((int)IExif.Tags.Orientation);
propertyItem = image.GetPropertyItem(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagOrientation);
if (propertyItem?.Value is not null)
orientation = BitConverter.ToInt16(propertyItem.Value, 0);
}
if (image.PropertyIdList.Contains((int)IExif.Tags.XPKeywords))
if (image.PropertyIdList.Contains(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagWinKeywords))
{
propertyItem = image.GetPropertyItem((int)IExif.Tags.XPKeywords);
propertyItem = image.GetPropertyItem(MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagWinKeywords);
if (propertyItem?.Value is not null)
{
if (propertyItem.Type == 2)
@ -333,7 +331,7 @@ internal partial class Property
{
try
{
directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(fileHolder.FullName);
IReadOnlyList<MetadataExtractor.Directory> directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(fileHolder.FullName);
(dateTimeOriginalByLogic, DateTime?[] metadataDateTimes) = metadata.GetDateTimes(fileHolder, directories);
dateTimesByLogic = GetDateTimes(dateTimes, metadataDateTimes);
message = null;

View File

@ -10,7 +10,6 @@ using View_by_Distance.Property.Models;
using View_by_Distance.Property.Models.Stateless;
using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Properties;
using View_by_Distance.Shared.Models.Stateless;
namespace View_by_Distance.Resize.Models;
@ -98,7 +97,7 @@ public class C_Resize
public static (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) GetGifLowQuality()
{
(ImageCodecInfo, EncoderParameters, string) result;
System.Drawing.Imaging.ImageFormat imageFormat = System.Drawing.Imaging.ImageFormat.Gif;
ImageFormat imageFormat = ImageFormat.Gif;
ImageCodecInfo imageCodecInfo = (from l in ImageCodecInfo.GetImageEncoders() where l.FormatID == imageFormat.Guid select l).First();
EncoderParameters encoderParameters = new(1);
encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 75L);
@ -111,7 +110,7 @@ public class C_Resize
public static (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) GetPngLowQuality()
{
(ImageCodecInfo, EncoderParameters, string) result;
System.Drawing.Imaging.ImageFormat imageFormat = System.Drawing.Imaging.ImageFormat.Png;
ImageFormat imageFormat = ImageFormat.Png;
ImageCodecInfo imageCodecInfo = (from l in ImageCodecInfo.GetImageEncoders() where l.FormatID == imageFormat.Guid select l).First();
EncoderParameters encoderParameters = new(1);
encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 75L);
@ -124,22 +123,22 @@ public class C_Resize
public static (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) GetTuple(string outputExtension, int outputQuality)
{
(ImageCodecInfo, EncoderParameters, string) result;
System.Drawing.Imaging.ImageFormat imageFormat = outputExtension switch
ImageFormat imageFormat = outputExtension switch
{
".gif" => System.Drawing.Imaging.ImageFormat.Gif,
".jfif" => System.Drawing.Imaging.ImageFormat.Jpeg,
".jpe" => System.Drawing.Imaging.ImageFormat.Jpeg,
".jpeg" => System.Drawing.Imaging.ImageFormat.Jpeg,
".jpg" => System.Drawing.Imaging.ImageFormat.Jpeg,
".png" => System.Drawing.Imaging.ImageFormat.Png,
".tif" => System.Drawing.Imaging.ImageFormat.Tiff,
".tiff" => System.Drawing.Imaging.ImageFormat.Tiff,
".gif" => ImageFormat.Gif,
".jfif" => ImageFormat.Jpeg,
".jpe" => ImageFormat.Jpeg,
".jpeg" => ImageFormat.Jpeg,
".jpg" => ImageFormat.Jpeg,
".png" => ImageFormat.Png,
".tif" => ImageFormat.Tiff,
".tiff" => ImageFormat.Tiff,
_ => throw new Exception(),
};
ImageCodecInfo imageCodecInfo = (from l in ImageCodecInfo.GetImageEncoders() where l.FormatID == imageFormat.Guid select l).First();
EncoderParameters encoderParameters = new(1);
// encoderParameters.Param[0] = New EncoderParameter(System.Drawing.Imaging.Encoder.Quality, CType(75L, Int32)) 'Default
// encoderParameters.Param[0] = New EncoderParameter(System.Drawing.Imaging.Encoder.Quality, CType(95L, Int32)) 'Paint
// encoderParameters.Param[0] = New EncoderParameter(Encoder.Quality, CType(75L, Int32)) 'Default
// encoderParameters.Param[0] = New EncoderParameter(Encoder.Quality, CType(95L, Int32)) 'Paint
encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, outputQuality);
if (string.IsNullOrEmpty(imageCodecInfo.FilenameExtension))
throw new NullReferenceException(nameof(imageCodecInfo.FilenameExtension));
@ -163,17 +162,17 @@ public class C_Resize
private void CopyPropertyItems(byte[] bytes, PropertyItem[] propertyItems, Bitmap bitmap)
{
bool hasId = false;
int id = (int)IExif.Tags.DateTimeDigitized;
int imageWidth = (int)IExif.Tags.ImageWidth;
int imageLength = (int)IExif.Tags.ImageLength;
int orientation = (int)IExif.Tags.Orientation;
int id = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagDateTimeDigitized;
int imageWidth = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagImageWidth;
int imageHeight = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagImageHeight;
int orientation = MetadataExtractor.Formats.Exif.ExifDirectoryBase.TagOrientation;
foreach (PropertyItem propertyItem in propertyItems)
{
if (propertyItem.Id == id)
hasId = true;
else if (propertyItem.Id == imageWidth)
continue;
else if (propertyItem.Id == imageLength)
else if (propertyItem.Id == imageHeight)
continue;
else if (propertyItem.Id == orientation)
continue;

View File

@ -3,20 +3,20 @@ using System.Text.Json.Serialization;
namespace View_by_Distance.Shared.Models;
public record ExifDirectory(AviDirectory AviDirectory,
ExifDirectoryBase ExifDirectoryBase,
string File,
FileMetadataDirectory FileMetadataDirectory,
GifHeaderDirectory GifHeaderDirectory,
GpsDirectory GpsDirectory,
public record ExifDirectory(AviDirectory[] AviDirectories,
ExifDirectoryBase[] ExifBaseDirectories,
FileMetadataDirectory[] FileMetadataDirectories,
GifHeaderDirectory[] GifHeaderDirectories,
GpsDirectory[] GpsDirectories,
int? Height,
string JsonFile,
JpegDirectory JpegDirectory,
PhotoshopDirectory PhotoshopDirectory,
PngDirectory PngDirectory,
QuickTimeMovieHeaderDirectory QuickTimeMovieHeaderDirectory,
QuickTimeTrackHeaderDirectory QuickTimeTrackHeaderDirectory,
WebPDirectory WebPDirectory,
JpegDirectory[] JpegDirectories,
MakernoteDirectory[] MakernoteDirectories,
string OriginalFileName,
PhotoshopDirectory[] PhotoshopDirectories,
PngDirectory[] PngDirectories,
QuickTimeMovieHeaderDirectory[] QuickTimeMovieHeaderDirectories,
QuickTimeTrackHeaderDirectory[] QuickTimeTrackHeaderDirectories,
WebPDirectory[] WebPDirectories,
int? Width)
{
@ -28,7 +28,7 @@ public record ExifDirectory(AviDirectory AviDirectory,
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
[JsonSerializable(typeof(ExifDirectory))]
public partial class ExifDirectorySourceGenerationContext : JsonSerializerContext
{

View File

@ -2,8 +2,8 @@ using System.Drawing;
namespace View_by_Distance.Shared.Models;
public record LocationContainer<T>(DateOnly CreationDateOnly,
IReadOnlyList<T> Directories,
public record LocationContainer(DateOnly CreationDateOnly,
ExifDirectory? ExifDirectory,
int? DirectoryNumber,
string DisplayDirectoryName,
FilePath FilePath,

View File

@ -0,0 +1,23 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace View_by_Distance.Shared.Models;
public record MakernoteDirectory(string? CameraSerialNumber,
string? FirmwareVersion,
string? QualityAndFileFormat)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, MakernoteDirectorySourceGenerationContext.Default.MakernoteDirectory);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(MakernoteDirectory))]
public partial class MakernoteDirectorySourceGenerationContext : JsonSerializerContext
{
}

View File

@ -2,9 +2,9 @@ using System.Collections.ObjectModel;
namespace View_by_Distance.Shared.Models.Methods;
public interface IDistance<T>
public interface IDistance
{
ReadOnlyCollection<RelationContainer> GetRelationContainers(int faceDistancePermyriad, int locationContainerDistanceTake, float locationContainerDistanceTolerance, ReadOnlyCollection<LocationContainer<T>> locationContainers);
ReadOnlyCollection<RelationContainer> GetRelationContainers(int faceDistancePermyriad, int locationContainerDistanceTake, float locationContainerDistanceTolerance, ReadOnlyCollection<LocationContainer> locationContainers);
}

View File

@ -4,7 +4,8 @@ using System.Text.Json.Serialization;
namespace View_by_Distance.Shared.Models;
public record PngDirectory(string? ImageHeight,
string? ImageWidth)
string? ImageWidth,
string? TextualData)
{
public override string ToString()

View File

@ -1,148 +1,148 @@
namespace View_by_Distance.Shared.Models.Stateless;
// namespace View_by_Distance.Shared.Models.Stateless;
public interface IExif
{
// public interface IExif
// {
enum Tags : ushort
{
GPSVersionID = 0,
GPSLatitudeRef = 1,
GPSLatitude = 2,
GPSLongitudeRef = 3,
GPSLongitude = 4,
GPSAltitudeRef = 5,
GPSAltitude = 6,
GPSTimestamp = 7,
GPSSatellites = 8,
GPSStatus = 9,
GPSMeasureMode = 10,
GPSDOP = 11,
GPSSpeedRef = 12,
GPSSpeed = 13,
GPSTrackRef = 14,
GPSTrack = 15,
GPSImgDirectionRef = 16,
GPSImgDirection = 17,
GPSMapDatum = 18,
GPSDestLatitudeRef = 19,
GPSDestLatitude = 20,
GPSDestLongitudeRef = 21,
GPSDestLongitude = 22,
GPSDestBearingRef = 23,
GPSDestBearing = 24,
GPSDestDistanceRef = 25,
GPSDestDistance = 26,
GPSProcessingMethod = 27,
GPSAreaInformation = 28,
GPSDateStamp = 29,
GPSDifferential = 30,
GPSHPositioningError = 31,
ImageWidth = 256,
ImageLength = 257,
BitsPerSample = 258,
Compression = 259,
PhotometricInterpretation = 262,
ImageDescription = 270,
Make = 271,
Model = 272,
StripOffsets = 273,
Orientation = 274,
SamplesPerPixel = 277,
RowsPerStrip = 278,
StripByteCounts = 279,
XResolution = 282,
YResolution = 283,
PlanarConfiguration = 284,
ResolutionUnit = 296,
TransferFunction = 301,
Software = 305,
DateTime = 306,
Artist = 315,
WhitePoint = 318,
PrimaryChromaticities = 319,
JPEGInterchangeFormat = 513,
JPEGInterchangeFormatLength = 514,
YCbCrCoefficients = 529,
YCbCrSubSampling = 530,
YCbCrPositioning = 531,
ReferenceBlackWhite = 532,
Copyright = 33432,
ExposureTime = 33434,
FNumber = 33437,
ExposureProgram = 34850,
SpectralSensitivity = 34852,
ISOSpeedRatings = 34855,
#pragma warning disable CA1069
PhotographicSensitivity = 34855,
#pragma warning restore CA1069
OECF = 34856,
SensitivityType = 34864,
StandardOutputSensitivity = 34865,
RecommendedExposureIndex = 34866,
ISOSpeed = 34867,
ISOSpeedLatitudeyyy = 34868,
ISOSpeedLatitudezzz = 34869,
ExifVersion = 36864,
DateTimeOriginal = 36867,
DateTimeDigitized = 36868,
ComponentsConfiguration = 37121,
CompressedBitsPerPixel = 37122,
ShutterSpeedValue = 37377,
ApertureValue = 37378,
BrightnessValue = 37379,
ExposureBiasValue = 37380,
MaxApertureValue = 37381,
SubjectDistance = 37382,
MeteringMode = 37383,
LightSource = 37384,
Flash = 37385,
FocalLength = 37386,
SubjectArea = 37396,
MakerNote = 37500,
UserComment = 37510,
SubsecTime = 37520,
SubsecTimeOriginal = 37521,
SubsecTimeDigitized = 37522,
XPTitle = 40091,
XPComment = 40092,
XPAuthor = 40093,
XPKeywords = 40094,
XPSubject = 40095,
FlashpixVersion = 40960,
ColorSpace = 40961,
PixelXDimension = 40962,
PixelYDimension = 40963,
RelatedSoundFile = 40964,
FlashEnergy = 41483,
SpatialFrequencyResponse = 41484,
FocalPlaneXResolution = 41486,
FocalPlaneYResolution = 41487,
FocalPlaneResolutionUnit = 41488,
SubjectLocation = 41492,
ExposureIndex = 41493,
SensingMethod = 41495,
FileSource = 41728,
SceneType = 41729,
CFAPattern = 41730,
CustomRendered = 41985,
ExposureMode = 41986,
WhiteBalance = 41987,
DigitalZoomRatio = 41988,
FocalLengthIn35mmFilm = 41989,
SceneCaptureType = 41990,
GainControl = 41991,
Contrast = 41992,
Saturation = 41993,
Sharpness = 41994,
DeviceSettingDescription = 41995,
SubjectDistanceRange = 41996,
ImageUniqueID = 42016,
CameraOwnerName = 42032,
BodySerialNumber = 42033,
LensSpecification = 42034,
LensMake = 42035,
LensModel = 42036,
LensSerialNumber = 42037
}
// enum Tags : ushort
// {
// GPSVersionID = 0,
// GPSLatitudeRef = 1,
// GPSLatitude = 2,
// GPSLongitudeRef = 3,
// GPSLongitude = 4,
// GPSAltitudeRef = 5,
// GPSAltitude = 6,
// GPSTimestamp = 7,
// GPSSatellites = 8,
// GPSStatus = 9,
// GPSMeasureMode = 10,
// GPSDOP = 11,
// GPSSpeedRef = 12,
// GPSSpeed = 13,
// GPSTrackRef = 14,
// GPSTrack = 15,
// GPSImgDirectionRef = 16,
// GPSImgDirection = 17,
// GPSMapDatum = 18,
// GPSDestLatitudeRef = 19,
// GPSDestLatitude = 20,
// GPSDestLongitudeRef = 21,
// GPSDestLongitude = 22,
// GPSDestBearingRef = 23,
// GPSDestBearing = 24,
// GPSDestDistanceRef = 25,
// GPSDestDistance = 26,
// GPSProcessingMethod = 27,
// GPSAreaInformation = 28,
// GPSDateStamp = 29,
// GPSDifferential = 30,
// GPSHPositioningError = 31,
// ImageWidth = 256,
// ImageLength = 257,
// BitsPerSample = 258,
// Compression = 259,
// PhotometricInterpretation = 262,
// ImageDescription = 270,
// Make = 271,
// Model = 272,
// StripOffsets = 273,
// Orientation = 274,
// SamplesPerPixel = 277,
// RowsPerStrip = 278,
// StripByteCounts = 279,
// XResolution = 282,
// YResolution = 283,
// PlanarConfiguration = 284,
// ResolutionUnit = 296,
// TransferFunction = 301,
// Software = 305,
// DateTime = 306,
// Artist = 315,
// WhitePoint = 318,
// PrimaryChromaticities = 319,
// JPEGInterchangeFormat = 513,
// JPEGInterchangeFormatLength = 514,
// YCbCrCoefficients = 529,
// YCbCrSubSampling = 530,
// YCbCrPositioning = 531,
// ReferenceBlackWhite = 532,
// Copyright = 33432,
// ExposureTime = 33434,
// FNumber = 33437,
// ExposureProgram = 34850,
// SpectralSensitivity = 34852,
// ISOSpeedRatings = 34855,
// #pragma warning disable CA1069
// PhotographicSensitivity = 34855,
// #pragma warning restore CA1069
// OECF = 34856,
// SensitivityType = 34864,
// StandardOutputSensitivity = 34865,
// RecommendedExposureIndex = 34866,
// ISOSpeed = 34867,
// ISOSpeedLatitudeyyy = 34868,
// ISOSpeedLatitudezzz = 34869,
// ExifVersion = 36864,
// DateTimeOriginal = 36867,
// DateTimeDigitized = 36868,
// ComponentsConfiguration = 37121,
// CompressedBitsPerPixel = 37122,
// ShutterSpeedValue = 37377,
// ApertureValue = 37378,
// BrightnessValue = 37379,
// ExposureBiasValue = 37380,
// MaxApertureValue = 37381,
// SubjectDistance = 37382,
// MeteringMode = 37383,
// LightSource = 37384,
// Flash = 37385,
// FocalLength = 37386,
// SubjectArea = 37396,
// MakerNote = 37500,
// UserComment = 37510,
// SubsecTime = 37520,
// SubsecTimeOriginal = 37521,
// SubsecTimeDigitized = 37522,
// XPTitle = 40091,
// XPComment = 40092,
// XPAuthor = 40093,
// XPKeywords = 40094,
// XPSubject = 40095,
// FlashpixVersion = 40960,
// ColorSpace = 40961,
// PixelXDimension = 40962,
// PixelYDimension = 40963,
// RelatedSoundFile = 40964,
// FlashEnergy = 41483,
// SpatialFrequencyResponse = 41484,
// FocalPlaneXResolution = 41486,
// FocalPlaneYResolution = 41487,
// FocalPlaneResolutionUnit = 41488,
// SubjectLocation = 41492,
// ExposureIndex = 41493,
// SensingMethod = 41495,
// FileSource = 41728,
// SceneType = 41729,
// CFAPattern = 41730,
// CustomRendered = 41985,
// ExposureMode = 41986,
// WhiteBalance = 41987,
// DigitalZoomRatio = 41988,
// FocalLengthIn35mmFilm = 41989,
// SceneCaptureType = 41990,
// GainControl = 41991,
// Contrast = 41992,
// Saturation = 41993,
// Sharpness = 41994,
// DeviceSettingDescription = 41995,
// SubjectDistanceRange = 41996,
// ImageUniqueID = 42016,
// CameraOwnerName = 42032,
// BodySerialNumber = 42033,
// LensSpecification = 42034,
// LensMake = 42035,
// LensModel = 42036,
// LensSerialNumber = 42037
// }
}
// }

View File

@ -25,9 +25,9 @@ public interface ILocation
static Models.Location? GetLocation(DatabaseFile databaseFile, Marker marker, Models.OutputResolution outputResolution) =>
Location.GetLocation(databaseFile, marker, outputResolution);
List<Models.Location> TestStatic_GetLocations<T>(List<LocationContainer<T>> locationContainers, List<Models.Face> faces, List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, float rectangleIntersectMinimum) =>
List<Models.Location> TestStatic_GetLocations(List<LocationContainer> locationContainers, List<Models.Face> faces, List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, float rectangleIntersectMinimum) =>
GetLocations(locationContainers, faces, mappingFromPhotoPrismCollection, rectangleIntersectMinimum);
static List<Models.Location> GetLocations<T>(List<LocationContainer<T>> locationContainers, List<Models.Face> faces, List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, float rectangleIntersectMinimum) =>
static List<Models.Location> GetLocations(List<LocationContainer> locationContainers, List<Models.Face> faces, List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, float rectangleIntersectMinimum) =>
Location.GetLocations(locationContainers, faces, mappingFromPhotoPrismCollection, rectangleIntersectMinimum);
RectangleF? TestStatic_GetPercentagesRectangle(int locationDigits, int wholePercentages) =>

View File

@ -245,7 +245,7 @@ internal abstract class Location
return result;
}
internal static List<Models.Location> GetLocations<T>(List<LocationContainer<T>> locationContainers, List<Models.Face> faces, List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, float rectangleIntersectMinimum)
internal static List<Models.Location> GetLocations(List<LocationContainer> locationContainers, List<Models.Face> faces, List<MappingFromPhotoPrism> mappingFromPhotoPrismCollection, float rectangleIntersectMinimum)
{
List<Models.Location> results = [];
bool any;
@ -266,7 +266,7 @@ internal abstract class Location
outputResolution ??= face.OutputResolution;
}
int before = results.Count;
foreach (LocationContainer<T> locationContainer in locationContainers)
foreach (LocationContainer locationContainer in locationContainers)
{
if (locationContainer.Location is null)
continue;
@ -289,7 +289,7 @@ internal abstract class Location
location = GetLocation(mappingFromPhotoPrism.DatabaseFile, marker, prismRectangle.Value);
if (location is null)
break;
foreach (LocationContainer<T> locationContainer in locationContainers)
foreach (LocationContainer locationContainer in locationContainers)
{
if (any)
continue;

View File

@ -1,7 +1,6 @@
using Microsoft.Extensions.Configuration;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Phares.Shared;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.Reflection;
@ -183,10 +182,10 @@ public class UnitTestResize
resize.SaveResizedSubfile(_PropertyConfiguration, outputResolution, cResultsFullGroupDirectory, subFileTuples, item, item.Property, mappingFromItem, outputResolutionToResize);
string blurHash = blurHasher.Encode(resizedFileHolder);
Assert.IsNotNull(blurHash);
ReadOnlyDictionary<string, MetadataExtractorDirectory> metadataExtractorDirectories = metadata.GetMetadataCollection(item.FilePath, subFileTuples, parseExceptions, changesFrom, mappingFromItem);
string json = JsonSerializer.Serialize(metadataExtractorDirectories, ReadOnlyDictionaryStringMetadataExtractorDirectorySourceGenerationContext.Default.ReadOnlyDictionaryStringMetadataExtractorDirectory);
ExifDirectory exifDirectory = metadata.GetMetadataCollection(item.FilePath, subFileTuples, parseExceptions, changesFrom, mappingFromItem);
string json = JsonSerializer.Serialize(exifDirectory, ExifDirectoryBaseSourceGenerationContext.Default.ExifDirectoryBase);
File.WriteAllText("../../../.json", json);
MetadataExtractor.GeoLocation? geoLocation = Metadata.Models.Stateless.Methods.IMetadata.GeoLocation(metadataExtractorDirectories);
MetadataExtractor.GeoLocation? geoLocation = Metadata.Models.Stateless.Methods.IMetadata.GeoLocation(exifDirectory);
double? distance = geoLocation is null ? null : Metadata.Models.Stateless.Methods.IMetadata.GetDistance(1, 1, geoLocation.Latitude, geoLocation.Longitude);
NonThrowTryCatch();
}

View File

@ -1,7 +1,6 @@
using Microsoft.Extensions.Configuration;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Phares.Shared;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.Reflection;
@ -251,14 +250,13 @@ public class UnitTestFace
resizedFileHolder = resize.GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber, filePath.Id.Value);
item.SetResizedFileHolder(resize.FileNameExtension, resizedFileHolder);
MappingFromItem mappingFromItem = IMappingFromItem.GetMappingFromItem(item);
IReadOnlyList<MetadataExtractor.Directory> directories = MetadataExtractor.ImageMetadataReader.ReadMetadata(resizedFileHolder.FullName);
Dictionary<string, int[]> outputResolutionToResize = resize.GetResizeKeyValuePairs(_PropertyConfiguration, cResultsFullGroupDirectory, item.FilePath, subFileTuples, parseExceptions, item.Property, mappingFromItem);
Assert.IsNotNull(mappingFromItem.ResizedFileHolder);
resize.SaveResizedSubfile(_PropertyConfiguration, outputResolution, cResultsFullGroupDirectory, subFileTuples, item, item.Property, mappingFromItem, outputResolutionToResize);
string blurHash = blurHasher.Encode(resizedFileHolder);
Assert.IsNotNull(blurHash);
ReadOnlyDictionary<string, MetadataExtractorDirectory>? metadataExtractorDirectories = metadata.GetMetadataCollection(item.FilePath, subFileTuples, parseExceptions, changesFrom, mappingFromItem);
string json = JsonSerializer.Serialize(metadataExtractorDirectories, ReadOnlyDictionaryStringMetadataExtractorDirectorySourceGenerationContext.Default.ReadOnlyDictionaryStringMetadataExtractorDirectory);
ExifDirectory exifDirectory = metadata.GetMetadataCollection(item.FilePath, subFileTuples, parseExceptions, changesFrom, mappingFromItem);
string json = JsonSerializer.Serialize(exifDirectory, ExifDirectoryBaseSourceGenerationContext.Default.ExifDirectoryBase);
File.WriteAllText("../../../.json", json);
Image image = FaceRecognition.LoadImageFile(mappingFromItem.ResizedFileHolder.FullName);
Assert.IsNotNull(image);