Exif Helper

This commit is contained in:
Mike Phares 2024-10-20 18:56:57 -07:00
parent 19326df4c6
commit 80ca8f98eb
29 changed files with 1287 additions and 10 deletions

1
.vscode/launch.json vendored
View File

@ -11,6 +11,7 @@
"preLaunchTask": "build", "preLaunchTask": "build",
"program": "${workspaceFolder}/bin/Debug/net8.0/win-x64/File-Folder-Helper.dll", "program": "${workspaceFolder}/bin/Debug/net8.0/win-x64/File-Folder-Helper.dll",
"args": [ "args": [
"D:/5-Other-Small/Proxmox/exiftool/286628400329.jpg.jpg",
"s", "s",
"X", "X",
"L:/DevOps/Mesa_FI/File-Folder-Helper/.vscode/helper/tfs", "L:/DevOps/Mesa_FI/File-Folder-Helper/.vscode/helper/tfs",

View File

@ -15,6 +15,7 @@
"CHIL", "CHIL",
"DEAT", "DEAT",
"endianness", "endianness",
"Exif",
"FAMC", "FAMC",
"FAMS", "FAMS",
"GIVN", "GIVN",
@ -29,6 +30,7 @@
"NSFX", "NSFX",
"OBJE", "OBJE",
"onenote", "onenote",
"Permyriad",
"pged", "pged",
"Phares", "Phares",
"Reparse", "Reparse",

View File

@ -15,6 +15,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="CommonMark.NET" Version="0.15.1" /> <PackageReference Include="CommonMark.NET" Version="0.15.1" />
<PackageReference Include="DiscUtils.Iso9660" Version="0.16.13" /> <PackageReference Include="DiscUtils.Iso9660" Version="0.16.13" />
<PackageReference Include="MetadataExtractor" Version="2.8.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" /> <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
<PackageReference Include="Microsoft.TeamFoundationServer.Client" Version="19.225.1" /> <PackageReference Include="Microsoft.TeamFoundationServer.Client" Version="19.225.1" />

126
Helpers/Exif/Dimensions.cs Normal file
View File

@ -0,0 +1,126 @@
using System.Drawing;
namespace File_Folder_Helper.Helpers.Exif;
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);
}
}

534
Helpers/Exif/Exif.cs Normal file
View File

@ -0,0 +1,534 @@
using MetadataExtractor;
using MetadataExtractor.Formats.Exif;
using MetadataExtractor.Formats.Exif.Makernotes;
using System.Globalization;
namespace File_Folder_Helper.Helpers.Exif;
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 Models.Exif.AviDirectory[] GetAviDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Models.Exif.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 Models.Exif.ExifDirectoryBase[] GetExifBaseDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Models.Exif.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 Models.Exif.FileMetadataDirectory[] GetFileMetadataDirectories(string file, IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Models.Exif.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 Models.Exif.GifHeaderDirectory[] GetGifHeaderDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Models.Exif.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 Models.Exif.GpsDirectory[] GetGpsDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Models.Exif.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 Models.Exif.JpegDirectory[] GetJpegDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Models.Exif.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 Models.Exif.MakernoteDirectory[] GetMakernoteDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Models.Exif.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 Models.Exif.PhotoshopDirectory[] GetPhotoshopDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Models.Exif.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 Models.Exif.PngDirectory[] GetPngDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Models.Exif.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 Models.Exif.QuickTimeMovieHeaderDirectory[] GetQuickTimeMovieHeaderDirectoryDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Models.Exif.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 Models.Exif.QuickTimeTrackHeaderDirectory[] GetQuickTimeTrackHeaderDirectoryDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Models.Exif.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 Models.Exif.WebPDirectory[] GetWebPDirectories(IReadOnlyList<MetadataExtractor.Directory> directories)
{
List<Models.Exif.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 Models.Exif.ExifDirectory Covert(FileInfo fileInfo, System.Drawing.Size? size, int id, IReadOnlyList<MetadataExtractor.Directory> directories)
{
Models.Exif.ExifDirectory result;
Models.Exif.AviDirectory[] aviDirectories = GetAviDirectories(directories);
Models.Exif.GpsDirectory[] gpsDirectories = GetGpsDirectories(directories);
Models.Exif.PngDirectory[] pngDirectories = GetPngDirectories(directories);
Models.Exif.JpegDirectory[] jpegDirectories = GetJpegDirectories(directories);
Models.Exif.WebPDirectory[] webPDirectories = GetWebPDirectories(directories);
Models.Exif.ExifDirectoryBase[] exifBaseDirectories = GetExifBaseDirectories(directories);
Models.Exif.GifHeaderDirectory[] gifHeaderDirectories = GetGifHeaderDirectories(directories);
Models.Exif.MakernoteDirectory[] MakernoteDirectories = GetMakernoteDirectories(directories);
Models.Exif.PhotoshopDirectory[] photoshopDirectories = GetPhotoshopDirectories(directories);
Models.Exif.FileMetadataDirectory[] fileMetadataDirectories = GetFileMetadataDirectories(fileInfo.FullName, directories);
Models.Exif.QuickTimeMovieHeaderDirectory[] quickTimeMovieHeaderDirectories = GetQuickTimeMovieHeaderDirectoryDirectories(directories);
Models.Exif.QuickTimeTrackHeaderDirectory[] quickTimeTrackHeaderDirectories = GetQuickTimeTrackHeaderDirectoryDirectories(directories);
result = new(aviDirectories,
exifBaseDirectories,
fileMetadataDirectories,
gifHeaderDirectories,
gpsDirectories,
size?.Height,
id,
jpegDirectories,
MakernoteDirectories,
fileInfo.Name,
photoshopDirectories,
pngDirectories,
quickTimeMovieHeaderDirectories,
quickTimeTrackHeaderDirectories,
webPDirectories,
size?.Width);
return result;
}
internal static Models.Exif.ExifDirectory GetExifDirectory(FileInfo fileInfo)
{
Models.Exif.ExifDirectory result;
int id = 1;
System.Drawing.Size? size;
try
{ size = Dimensions.GetDimensions(fileInfo.FullName); }
catch (Exception)
{ size = null; }
IReadOnlyList<MetadataExtractor.Directory> directories = ImageMetadataReader.ReadMetadata(fileInfo.FullName);
result = Covert(fileInfo, size, id, directories);
return result;
}
}

View File

@ -0,0 +1,49 @@
using File_Folder_Helper.Models.Exif;
using File_Folder_Helper.Models.Face;
using Microsoft.Extensions.Logging;
using System.Collections.ObjectModel;
using System.Text.Json;
namespace File_Folder_Helper.Helpers.Exif;
internal static class HelperExif
{
private static ReadOnlyCollection<FaceFile> GetCollection(ExifDirectoryBase[]? exifDirectoryBases)
{
List<FaceFile> results = [];
if (exifDirectoryBases is not null)
{
string? json;
FaceFile[]? collection;
foreach (ExifDirectoryBase exifDirectoryBase in exifDirectoryBases)
{
json = exifDirectoryBase.Artist;
if (string.IsNullOrEmpty(json))
continue;
collection = JsonSerializer.Deserialize(json, FaceFileCollectionGenerationContext.Default.FaceFileArray);
if (collection is null)
continue;
results.AddRange(collection);
}
}
return new(results);
}
internal static void DragAndDrop(ILogger<Worker> logger, string argZero)
{
FileInfo fileInfo = new(argZero);
logger.LogInformation("<{argZero}> exists", argZero);
ExifDirectory exifDirectory = Exif.GetExifDirectory(fileInfo);
ReadOnlyCollection<FaceFile> collection = GetCollection(exifDirectory.ExifBaseDirectories);
logger.LogInformation("<{collection}> value", collection.Count);
foreach (FaceFile faceFile in collection)
{
if (faceFile.MappingFromPerson is null)
logger.LogInformation("<{Confidence}> value", faceFile.Location?.Confidence);
else
logger.LogInformation("<{DisplayDirectoryName}> value", faceFile.MappingFromPerson.DisplayDirectoryName);
}
}
}

View File

@ -9,6 +9,7 @@ public record AppSettings(string Company,
string[] ExcludeSchemes, string[] ExcludeSchemes,
string PersonBirthdayFormat, string PersonBirthdayFormat,
char[] PersonTitleFilters, char[] PersonTitleFilters,
string[] ValidImageFormatExtensions,
string WorkingDirectoryName) string WorkingDirectoryName)
{ {

View File

@ -13,6 +13,7 @@ public class AppSettings
public string[]? ExcludeSchemes { get; set; } public string[]? ExcludeSchemes { get; set; }
public string? PersonBirthdayFormat { get; set; } public string? PersonBirthdayFormat { get; set; }
public string? PersonTitleFilters { get; set; } public string? PersonTitleFilters { get; set; }
public string[]? ValidImageFormatExtensions { get; set; }
public string? WorkingDirectoryName { get; set; } public string? WorkingDirectoryName { get; set; }
public override string ToString() public override string ToString()
@ -47,20 +48,20 @@ public class AppSettings
if (appSettings?.ExcludeSchemes is null) throw new NullReferenceException(nameof(appSettings.ExcludeSchemes)); if (appSettings?.ExcludeSchemes is null) throw new NullReferenceException(nameof(appSettings.ExcludeSchemes));
if (appSettings?.PersonBirthdayFormat is null) throw new NullReferenceException(nameof(appSettings.PersonBirthdayFormat)); if (appSettings?.PersonBirthdayFormat is null) throw new NullReferenceException(nameof(appSettings.PersonBirthdayFormat));
if (appSettings?.PersonTitleFilters is null) throw new NullReferenceException(nameof(appSettings.PersonTitleFilters)); if (appSettings?.PersonTitleFilters is null) throw new NullReferenceException(nameof(appSettings.PersonTitleFilters));
if (appSettings?.ValidImageFormatExtensions is null) throw new NullReferenceException(nameof(appSettings.ValidImageFormatExtensions));
if (appSettings?.WorkingDirectoryName is null) throw new NullReferenceException(nameof(appSettings.WorkingDirectoryName)); if (appSettings?.WorkingDirectoryName is null) throw new NullReferenceException(nameof(appSettings.WorkingDirectoryName));
result = new( result = new(appSettings.Company,
appSettings.Company,
appSettings.DefaultNoteType, appSettings.DefaultNoteType,
appSettings.ExcludeDirectoryNames, appSettings.ExcludeDirectoryNames,
appSettings.ExcludeSchemes, appSettings.ExcludeSchemes,
appSettings.PersonBirthdayFormat, appSettings.PersonBirthdayFormat,
appSettings.PersonTitleFilters.ToArray(), appSettings.PersonTitleFilters.ToArray(),
appSettings.WorkingDirectoryName appSettings.ValidImageFormatExtensions,
); appSettings.WorkingDirectoryName);
return result; return result;
} }
internal static Models.AppSettings Get(IConfigurationRoot configurationRoot) public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
{ {
Models.AppSettings result; Models.AppSettings result;
#pragma warning disable IL3050, IL2026 #pragma warning disable IL3050, IL2026

View File

@ -0,0 +1,24 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Folder_Helper.Models.Exif;
public record AviDirectory(DateTime? DateTimeOriginal,
string? Duration,
string? Height,
string? Width)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, AviDirectorySourceGenerationContext.Default.AviDirectory);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(AviDirectory))]
public partial class AviDirectorySourceGenerationContext : JsonSerializerContext
{
}

View File

@ -0,0 +1,36 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Folder_Helper.Models.Exif;
public record ExifDirectory(AviDirectory[] AviDirectories,
ExifDirectoryBase[] ExifBaseDirectories,
FileMetadataDirectory[] FileMetadataDirectories,
GifHeaderDirectory[] GifHeaderDirectories,
GpsDirectory[] GpsDirectories,
int? Height,
int? Id,
JpegDirectory[] JpegDirectories,
MakernoteDirectory[] MakernoteDirectories,
string OriginalFileName,
PhotoshopDirectory[] PhotoshopDirectories,
PngDirectory[] PngDirectories,
QuickTimeMovieHeaderDirectory[] QuickTimeMovieHeaderDirectories,
QuickTimeTrackHeaderDirectory[] QuickTimeTrackHeaderDirectories,
WebPDirectory[] WebPDirectories,
int? Width)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
[JsonSerializable(typeof(ExifDirectory))]
public partial class ExifDirectorySourceGenerationContext : JsonSerializerContext
{
}

View File

@ -0,0 +1,66 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Folder_Helper.Models.Exif;
public record ExifDirectoryBase(string? Aperture,
string? ApplicationNotes,
string? Artist,
string? BitsPerSample,
string? BodySerialNumber,
string? CameraOwnerName,
string? CompressedAverageBitsPerPixel,
string? Compression,
string? Copyright,
DateTime? DateTime,
DateTime? DateTimeDigitized,
DateTime? DateTimeOriginal,
string? DocumentName,
string? ExifVersion,
string? ExposureTime,
string? FileSource,
string? ImageDescription,
string? ImageHeight,
string? ImageNumber,
string? ImageUniqueId,
string? ImageWidth,
string? IsoSpeed,
string? LensMake,
string? LensModel,
string? LensSerialNumber,
string? Make,
string? MakerNote,
string? Model,
string? Orientation,
int? OrientationValue,
string? Rating,
string? RatingPercent,
string? SecurityClassification,
string? ShutterSpeed,
string? Software,
string? TimeZone,
string? TimeZoneDigitized,
string? TimeZoneOriginal,
string? UserComment,
string? WinAuthor,
string? WinComment,
string? WinKeywords,
string? WinSubject,
string? WinTitle,
string? XResolution,
string? YResolution)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, ExifDirectoryBaseSourceGenerationContext.Default.ExifDirectoryBase);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(ExifDirectoryBase))]
public partial class ExifDirectoryBaseSourceGenerationContext : JsonSerializerContext
{
}

View File

@ -0,0 +1,23 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Folder_Helper.Models.Exif;
public record FileMetadataDirectory(DateTime? FileModifiedDate,
string? FileName,
string? FileSize)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, FileMetadataDirectorySourceGenerationContext.Default.FileMetadataDirectory);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(FileMetadataDirectory))]
public partial class FileMetadataDirectorySourceGenerationContext : JsonSerializerContext
{
}

View File

@ -0,0 +1,22 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Folder_Helper.Models.Exif;
public record GifHeaderDirectory(string? ImageHeight,
string? ImageWidth)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, GifHeaderDirectorySourceGenerationContext.Default.GifHeaderDirectory);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(GifHeaderDirectory))]
public partial class GifHeaderDirectorySourceGenerationContext : JsonSerializerContext
{
}

View File

@ -0,0 +1,26 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Folder_Helper.Models.Exif;
public record GpsDirectory(string? Altitude,
string? Latitude,
string? LatitudeRef,
string? Longitude,
string? LongitudeRef,
DateTime? TimeStamp)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, GpsDirectorySourceGenerationContext.Default.GpsDirectory);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(GpsDirectory))]
public partial class GpsDirectorySourceGenerationContext : JsonSerializerContext
{
}

View File

@ -0,0 +1,22 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Folder_Helper.Models.Exif;
public record JpegDirectory(string? ImageHeight,
string? ImageWidth)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, JpegDirectorySourceGenerationContext.Default.JpegDirectory);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(JpegDirectory))]
public partial class JpegDirectorySourceGenerationContext : JsonSerializerContext
{
}

View File

@ -0,0 +1,23 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Folder_Helper.Models.Exif;
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

@ -0,0 +1,22 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Folder_Helper.Models.Exif;
public record PhotoshopDirectory(string? JpegQuality,
string? Url)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, PhotoshopDirectorySourceGenerationContext.Default.PhotoshopDirectory);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(PhotoshopDirectory))]
public partial class PhotoshopDirectorySourceGenerationContext : JsonSerializerContext
{
}

View File

@ -0,0 +1,23 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Folder_Helper.Models.Exif;
public record PngDirectory(string? ImageHeight,
string? ImageWidth,
string? TextualData)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, PngDirectorySourceGenerationContext.Default.PngDirectory);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(PngDirectory))]
public partial class PngDirectorySourceGenerationContext : JsonSerializerContext
{
}

View File

@ -0,0 +1,21 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Folder_Helper.Models.Exif;
public record QuickTimeMovieHeaderDirectory(DateTime? Created)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, QuickTimeMovieHeaderDirectorySourceGenerationContext.Default.QuickTimeMovieHeaderDirectory);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(QuickTimeMovieHeaderDirectory))]
public partial class QuickTimeMovieHeaderDirectorySourceGenerationContext : JsonSerializerContext
{
}

View File

@ -0,0 +1,21 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Folder_Helper.Models.Exif;
public record QuickTimeTrackHeaderDirectory(DateTime? Created)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, QuickTimeTrackHeaderDirectorySourceGenerationContext.Default.QuickTimeTrackHeaderDirectory);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(QuickTimeTrackHeaderDirectory))]
public partial class QuickTimeTrackHeaderDirectorySourceGenerationContext : JsonSerializerContext
{
}

View File

@ -0,0 +1,22 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Folder_Helper.Models.Exif;
public record WebPDirectory(string? ImageHeight,
string? ImageWidth)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, WebPDirectorySourceGenerationContext.Default.WebPDirectory);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(WebPDirectory))]
public partial class WebPDirectorySourceGenerationContext : JsonSerializerContext
{
}

View File

@ -0,0 +1,11 @@
using System.Text.Json.Serialization;
namespace File_Folder_Helper.Models.Face;
public record FaceEncoding(double[] RawEncoding, int Size);
[JsonSourceGenerationOptions(WriteIndented = false)]
[JsonSerializable(typeof(FaceEncoding))]
public partial class FaceEncodingGenerationContext : JsonSerializerContext
{
}

33
Models/Face/FaceFile.cs Normal file
View File

@ -0,0 +1,33 @@
using System.Text.Json.Serialization;
namespace File_Folder_Helper.Models.Face;
public record FaceFile(int? AreaPermyriad,
int? ConfidencePercent,
string? DMS,
DateTime DateTime,
FaceEncoding? FaceEncoding,
Dictionary<FacePart, FacePoint[]>? FaceParts,
Location? Location,
string? Maker,
MappingFromPerson? MappingFromPerson,
string? Model,
OutputResolution? OutputResolution);
[JsonSourceGenerationOptions(WriteIndented = false)]
[JsonSerializable(typeof(FaceFile))]
public partial class FaceFileGenerationContext : JsonSerializerContext
{
}
[JsonSourceGenerationOptions(WriteIndented = false, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
[JsonSerializable(typeof(FaceFile[]))]
public partial class FaceFileCollectionGenerationContext : JsonSerializerContext
{
}
[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
[JsonSerializable(typeof(FaceFile[]))]
public partial class FaceFileCollectionWriteIndentedGenerationContext : JsonSerializerContext
{
}

54
Models/Face/FacePart.cs Normal file
View File

@ -0,0 +1,54 @@
namespace File_Folder_Helper.Models.Face;
/// <summary>
/// Specifies the part of face.
/// </summary>
public enum FacePart
{
/// <summary>
/// Specifies the chin.
/// </summary>
Chin = 0,
/// <summary>
/// Specifies the left eyebrow.
/// </summary>
LeftEyebrow = 17,
/// <summary>
/// Specifies the right eyebrow.
/// </summary>
RightEyebrow = 22,
/// <summary>
/// Specifies the nose bridge.
/// </summary>
NoseBridge = 27,
/// <summary>
/// Specifies the nose tip.
/// </summary>
NoseTip = 31,
/// <summary>
/// Specifies the left eye.
/// </summary>
LeftEye = 36,
/// <summary>
/// Specifies the right eye.
/// </summary>
RightEye = 42,
/// <summary>
/// Specifies the top lip.
/// </summary>
TopLip = 48,
/// <summary>
/// Specifies the bottom lip.
/// </summary>
BottomLip = 55
}

39
Models/Face/FacePoint.cs Normal file
View File

@ -0,0 +1,39 @@
using System.Drawing;
using System.Text.Json.Serialization;
namespace File_Folder_Helper.Models.Face;
[method: JsonConstructor]
public class FacePoint(int index, int x, int y)
{
public int Index { get; } = index;
public int X { get; } = x;
public int Y { get; } = y;
private readonly Point _Point = new(x, y);
public override bool Equals(object? obj) => obj is FacePoint point && Equals(point);
#pragma warning disable IDE0070
public override int GetHashCode()
#pragma warning restore IDE0070
{
int hashCode = 1861411795;
hashCode = (hashCode * -1521134295) + _Point.GetHashCode();
hashCode = (hashCode * -1521134295) + Index.GetHashCode();
return hashCode;
}
public bool Equals(FacePoint? facePoint)
{
return facePoint is not null
&& X == facePoint.X
&& Y == facePoint.Y
&& Index == facePoint.Index;
}
public static bool operator ==(FacePoint point1, FacePoint point2) => point1.Equals(point2);
public static bool operator !=(FacePoint point1, FacePoint point2) => !(point1 == point2);
}

42
Models/Face/Location.cs Normal file
View File

@ -0,0 +1,42 @@
using System.Text.Json.Serialization;
namespace File_Folder_Helper.Models.Face;
[method: JsonConstructor]
public class Location(int bottom, double confidence, int left, int right, int top) : IEquatable<Location>
{
public int Bottom { init; get; } = bottom;
public double Confidence { init; get; } = confidence;
public int Left { init; get; } = left;
public int Right { init; get; } = right;
public int Top { init; get; } = top;
public override bool Equals(object? obj) => Equals(obj as Location);
#pragma warning disable IDE0070
public override int GetHashCode()
#pragma warning restore IDE0070
{
int hashCode = -773114317;
hashCode = (hashCode * -1521134295) + Bottom.GetHashCode();
hashCode = (hashCode * -1521134295) + Left.GetHashCode();
hashCode = (hashCode * -1521134295) + Right.GetHashCode();
hashCode = (hashCode * -1521134295) + Top.GetHashCode();
return hashCode;
}
public bool Equals(Location? location)
{
return location is not null
&& Bottom == location.Bottom
&& Left == location.Left
&& Right == location.Right
&& Top == location.Top;
}
public static bool operator ==(Location location1, Location location2) => EqualityComparer<Location>.Default.Equals(location1, location2);
public static bool operator !=(Location location1, Location location2) => !(location1 == location2);
}

View File

@ -0,0 +1,24 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Folder_Helper.Models.Face;
public record MappingFromPerson(int? ApproximateYears,
string DisplayDirectoryName,
long PersonKey,
string SegmentB)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, MappingFromPersonGenerationContext.Default.MappingFromPerson);
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(MappingFromPerson))]
public partial class MappingFromPersonGenerationContext : JsonSerializerContext
{
}

View File

@ -0,0 +1,5 @@
namespace File_Folder_Helper.Models.Face;
public record OutputResolution(int Height,
int Orientation,
int Width);

View File

@ -136,6 +136,7 @@ public class Worker : BackgroundService
break; break;
} }
} }
string extension = Path.GetExtension(_Args[0]);
if (consoleKey is not ConsoleKey.End && !_ConsoleKeys.Contains(consoleKey)) if (consoleKey is not ConsoleKey.End && !_ConsoleKeys.Contains(consoleKey))
consoleKey = ConsoleKey.End; consoleKey = ConsoleKey.End;
if (singleCharIndex is not null) if (singleCharIndex is not null)
@ -233,6 +234,8 @@ public class Worker : BackgroundService
break; break;
} }
} }
else if (_AppSettings.ValidImageFormatExtensions.Contains(extension) && File.Exists(_Args[0]))
Helpers.Exif.HelperExif.DragAndDrop(_Logger, _Args[0]);
else else
throw new Exception(_Args[0]); throw new Exception(_Args[0]);
} }