Metadata
This commit is contained in:
@ -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]);
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
{
|
||||
}
|
@ -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
|
||||
{
|
||||
}
|
@ -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
|
||||
{
|
||||
}
|
@ -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
|
||||
{
|
||||
}
|
54
Metadata/Models/Stateless/Base.cs
Normal file
54
Metadata/Models/Stateless/Base.cs
Normal 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;
|
||||
}
|
||||
|
||||
}
|
126
Metadata/Models/Stateless/Dimensions.cs
Normal file
126
Metadata/Models/Stateless/Dimensions.cs
Normal 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);
|
||||
}
|
||||
|
||||
}
|
529
Metadata/Models/Stateless/Exif.cs
Normal file
529
Metadata/Models/Stateless/Exif.cs
Normal 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;
|
||||
}
|
||||
|
||||
}
|
42
Metadata/Models/Stateless/Face.cs
Normal file
42
Metadata/Models/Stateless/Face.cs
Normal 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;
|
||||
}
|
||||
|
||||
}
|
121
Metadata/Models/Stateless/GPS.cs
Normal file
121
Metadata/Models/Stateless/GPS.cs
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user