Removed Obsolete A_Property Methods
Changed GetDimensions to handle a stream at the end and one exit Switched to using Action? over IDlibDotNet for Tick method Switched to using AsReadOnly over new() Moved Meta Base to Shared
This commit is contained in:
149
Shared/Models/Stateless/Methods/Dimensions.cs
Normal file
149
Shared/Models/Stateless/Methods/Dimensions.cs
Normal file
@ -0,0 +1,149 @@
|
||||
using System.Drawing;
|
||||
|
||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
internal static class Dimensions
|
||||
{
|
||||
|
||||
#pragma warning disable IDE0230
|
||||
private static readonly Dictionary<byte[], Func<BinaryReader, Size?>> _ImageFormatDecoders = new()
|
||||
{
|
||||
{ new byte[] { 0xff, 0xd8 }, DecodeJfif },
|
||||
{ new byte[] { 0x42, 0x4D }, DecodeBitmap },
|
||||
{ new byte[] { 0x52, 0x49, 0x46, 0x46 }, DecodeWebP },
|
||||
{ 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 },
|
||||
};
|
||||
#pragma warning restore IDE0230
|
||||
|
||||
private static bool StartsWith(List<byte> thisBytes, byte[] thatBytes)
|
||||
{
|
||||
for (int i = 0; i < thisBytes.Count && 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? faceRight, int? faceBottom)
|
||||
{
|
||||
Size? result;
|
||||
List<byte> magicBytes = [];
|
||||
int[] magicBytesLengths = (from l in _ImageFormatDecoders.Keys where l.Length <= binaryReader.BaseStream.Length orderby l.Length descending select l.Length).ToArray();
|
||||
if (magicBytesLengths.Length == 0)
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
result = null;
|
||||
if (binaryReader.BaseStream.Length == binaryReader.BaseStream.Position)
|
||||
_ = binaryReader.BaseStream.Seek(0, SeekOrigin.Begin);
|
||||
for (int i = 0; i < magicBytesLengths[0]; i++)
|
||||
{
|
||||
magicBytes.Add(binaryReader.ReadByte());
|
||||
foreach (KeyValuePair<byte[], Func<BinaryReader, Size?>> kvPair in _ImageFormatDecoders)
|
||||
{
|
||||
if (StartsWith(magicBytes, kvPair.Key))
|
||||
{
|
||||
result = kvPair.Value(binaryReader);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result is not null)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result is null)
|
||||
{
|
||||
if (faceRight is null || faceBottom is null)
|
||||
throw new Exception("face is null!");
|
||||
result = new(faceRight.Value, faceBottom.Value);
|
||||
}
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
internal static Size GetDimensions(string path, int? faceRight, int? faceBottom)
|
||||
{
|
||||
Size result;
|
||||
using FileStream fileStream = File.OpenRead(path);
|
||||
using BinaryReader binaryReader = new(fileStream);
|
||||
result = GetDimensions(binaryReader, faceRight, faceBottom);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -7,29 +7,22 @@ internal abstract class FilePair
|
||||
{
|
||||
|
||||
internal static ReadOnlyCollection<Models.FilePair> GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection)
|
||||
{
|
||||
ReadOnlyCollection<Models.FilePair> results;
|
||||
ReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles = FilePath.GetFilesKeyValuePairs(filePathsCollection);
|
||||
results = GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection, fileNamesToFiles);
|
||||
return results;
|
||||
}
|
||||
|
||||
internal static ReadOnlyCollection<Models.FilePair> GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles)
|
||||
{
|
||||
List<Models.FilePair>? results = null;
|
||||
int renamed;
|
||||
const bool useCeilingAverage = true;
|
||||
ReadOnlyCollection<string[]>? jsonFilesCollection = null;
|
||||
IReadOnlyDictionary<int, List<FilePath>>? compareFileNamesToFiles = null;
|
||||
for (int i = 0; i < fileNamesToFiles.Count; i++)
|
||||
ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> idToFilePaths = FilePath.GetKeyValuePairs(filePathsCollection);
|
||||
IReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? compareFileNamesToFiles = null;
|
||||
for (int i = 0; i < idToFilePaths.Count; i++)
|
||||
{
|
||||
renamed = 0;
|
||||
jsonFilesCollection = XDirectory.GetFilesCollection(jsonGroupDirectory, directorySearchFilter, extension, useCeilingAverage);
|
||||
renamed += LookForAbandoned(propertyConfiguration, jsonFilesCollection, fileNamesToFiles, extension);
|
||||
renamed += LookForAbandoned(propertyConfiguration, jsonFilesCollection, idToFilePaths, extension);
|
||||
if (renamed > 0)
|
||||
continue;
|
||||
compareFileNamesToFiles = GetKeyValuePairs(propertyConfiguration, jsonFilesCollection);
|
||||
results = XDirectory.GetFiles(propertyConfiguration, filePathsCollection, fileNamesToFiles, compareFileNamesToFiles);
|
||||
results = XDirectory.GetFiles(propertyConfiguration, filePathsCollection, idToFilePaths, compareFileNamesToFiles);
|
||||
renamed += XDirectory.MaybeMove(propertyConfiguration, results, jsonGroupDirectory, extension);
|
||||
if (renamed == 0)
|
||||
break;
|
||||
@ -41,7 +34,7 @@ internal abstract class FilePair
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static int LookForAbandoned(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> jsonFilesCollection, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, string extension)
|
||||
private static int LookForAbandoned(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> jsonFilesCollection, IReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> fileNamesToFiles, string extension)
|
||||
{
|
||||
int result;
|
||||
bool check;
|
||||
@ -63,7 +56,7 @@ internal abstract class FilePair
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool AnyMoved(IPropertyConfiguration propertyConfiguration, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, string extension, List<string> renameCollection, string[] files)
|
||||
private static bool AnyMoved(IPropertyConfiguration propertyConfiguration, IReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> fileNamesToFiles, string extension, List<string> renameCollection, string[] files)
|
||||
{
|
||||
bool result = false;
|
||||
string checkFile;
|
||||
@ -72,11 +65,13 @@ internal abstract class FilePair
|
||||
string fileNameWith;
|
||||
string checkDirectory;
|
||||
string directoryName;
|
||||
List<FilePath>? collection;
|
||||
Models.FileHolder fileHolder;
|
||||
List<string> directoryNames = [];
|
||||
ReadOnlyCollection<FilePath>? collection;
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (files.Any(l => l.StartsWith(propertyConfiguration.RootDirectory)))
|
||||
continue;
|
||||
if (!file.EndsWith(extension))
|
||||
throw new Exception();
|
||||
fileHolder = IFileHolder.Get(file);
|
||||
@ -120,12 +115,13 @@ internal abstract class FilePair
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<int, List<FilePath>> GetKeyValuePairs(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection)
|
||||
private static ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> GetKeyValuePairs(IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<string[]> filesCollection)
|
||||
{
|
||||
Dictionary<int, List<FilePath>> results = [];
|
||||
List<FilePath>? collection;
|
||||
Dictionary<int, ReadOnlyCollection<FilePath>> results = [];
|
||||
FilePath filePath;
|
||||
List<FilePath>? collection;
|
||||
Models.FileHolder fileHolder;
|
||||
Dictionary<int, List<FilePath>> keyValuePairs = [];
|
||||
foreach (string[] files in filesCollection)
|
||||
{
|
||||
foreach (string file in files)
|
||||
@ -136,15 +132,17 @@ internal abstract class FilePair
|
||||
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
||||
if (filePath.Id is null)
|
||||
continue;
|
||||
if (!results.TryGetValue(filePath.Id.Value, out collection))
|
||||
if (!keyValuePairs.TryGetValue(filePath.Id.Value, out collection))
|
||||
{
|
||||
results.Add(filePath.Id.Value, []);
|
||||
if (!results.TryGetValue(filePath.Id.Value, out collection))
|
||||
keyValuePairs.Add(filePath.Id.Value, []);
|
||||
if (!keyValuePairs.TryGetValue(filePath.Id.Value, out collection))
|
||||
throw new Exception();
|
||||
}
|
||||
collection.Add(filePath);
|
||||
}
|
||||
}
|
||||
foreach (KeyValuePair<int, List<FilePath>> keyValuePair in keyValuePairs)
|
||||
results.Add(keyValuePair.Key, keyValuePair.Value.AsReadOnly());
|
||||
return new(results);
|
||||
}
|
||||
|
||||
|
@ -29,13 +29,13 @@ public interface IDirectory
|
||||
public static ReadOnlyCollection<ReadOnlyCollection<FilePath>> GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string fileSearchFilter, string directory, bool useIgnoreExtensions, bool useCeilingAverage) =>
|
||||
XDirectory.GetFilePathCollections(propertyConfiguration, directorySearchFilter, fileSearchFilter, directory, useIgnoreExtensions, useCeilingAverage);
|
||||
|
||||
public static List<Models.FilePair> GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, IReadOnlyDictionary<int, List<FilePath>> compareFileNamesToFiles) =>
|
||||
public static List<Models.FilePair> GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> fileNamesToFiles, IReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> compareFileNamesToFiles) =>
|
||||
XDirectory.GetFiles(propertyConfiguration, filePathsCollection, fileNamesToFiles, compareFileNamesToFiles);
|
||||
|
||||
public static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<byte, ReadOnlyCollection<string>> fileGroups, Action? tick) =>
|
||||
XDirectory.GetToDoCollection(propertyConfiguration, copyDuplicates, ifCanUseId, filePathsCollection, fileGroups, null, tick);
|
||||
|
||||
public static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<byte, ReadOnlyCollection<string>> fileGroups, Dictionary<int, ExifDirectory> exifDirectoriesById, Action? tick) =>
|
||||
public static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<byte, ReadOnlyCollection<string>> fileGroups, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById, Action? tick) =>
|
||||
XDirectory.GetToDoCollection(propertyConfiguration, copyDuplicates: false, ifCanUseId: true, filePathsCollection, fileGroups, exifDirectoriesById, tick);
|
||||
|
||||
internal int TestStatic_GetDirectory(char directory) =>
|
||||
@ -62,13 +62,13 @@ public interface IDirectory
|
||||
internal ReadOnlyCollection<ReadOnlyCollection<FilePath>> TestStatic_GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string fileSearchFilter, string directory, bool useIgnoreExtensions, bool useCeilingAverage) =>
|
||||
GetFilePathCollections(propertyConfiguration, directorySearchFilter, fileSearchFilter, directory, useIgnoreExtensions, useCeilingAverage);
|
||||
|
||||
internal List<Models.FilePair> TestStatic_GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, IReadOnlyDictionary<int, List<FilePath>> compareFileNamesToFiles) =>
|
||||
internal List<Models.FilePair> TestStatic_GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> fileNamesToFiles, IReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> compareFileNamesToFiles) =>
|
||||
GetFiles(propertyConfiguration, filePathsCollection, fileNamesToFiles, compareFileNamesToFiles);
|
||||
|
||||
internal (string[], List<(FilePath, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<byte, ReadOnlyCollection<string>> fileGroups, Action? tick) =>
|
||||
GetToDoCollection(propertyConfiguration, copyDuplicates, ifCanUseId, filePathsCollection, fileGroups, tick);
|
||||
|
||||
internal (string[], List<(FilePath, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<byte, ReadOnlyCollection<string>> fileGroups, Dictionary<int, ExifDirectory> exifDirectoriesById, Action? tick) =>
|
||||
internal (string[], List<(FilePath, string)>) TestStatic_GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<byte, ReadOnlyCollection<string>> fileGroups, ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById, Action? tick) =>
|
||||
GetToDoCollection(propertyConfiguration, filePathsCollection, fileGroups, exifDirectoriesById, tick);
|
||||
|
||||
}
|
@ -4,6 +4,7 @@ public interface IDlibDotNet
|
||||
{
|
||||
|
||||
void Tick();
|
||||
long Ticks { get; }
|
||||
(string, string) GetResultsFullGroupDirectories();
|
||||
void ConstructProgressBar(int maxTicks, string message);
|
||||
(string, string, string, string) GetResultsFullGroupDirectories(string outputResolution);
|
||||
|
@ -9,13 +9,7 @@ public interface IFilePair
|
||||
public static ReadOnlyCollection<Models.FilePair> GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection) =>
|
||||
FilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection);
|
||||
|
||||
public static ReadOnlyCollection<Models.FilePair> GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles) =>
|
||||
FilePair.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection, fileNamesToFiles);
|
||||
|
||||
internal ReadOnlyCollection<Models.FilePair> TestStatic_GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection) =>
|
||||
GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection);
|
||||
|
||||
internal ReadOnlyCollection<Models.FilePair> TestStatic_GetFilePairs(IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string jsonGroupDirectory, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles) =>
|
||||
GetFilePairs(propertyConfiguration, directorySearchFilter, extension, jsonGroupDirectory, filePathsCollection, fileNamesToFiles);
|
||||
|
||||
}
|
@ -5,24 +5,66 @@ namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
public interface IMetaBase
|
||||
{
|
||||
|
||||
public static string DateTimeFormat() =>
|
||||
"yyyy:MM:dd HH:mm:ss";
|
||||
|
||||
public static string? GetMaker(ExifDirectory? exifDirectory) =>
|
||||
MetaBase.GetMaker(exifDirectory?.ExifBaseDirectories);
|
||||
|
||||
public static string? GetModel(ExifDirectory? exifDirectory) =>
|
||||
MetaBase.GetModel(exifDirectory?.ExifBaseDirectories);
|
||||
|
||||
public static int? GetOrientation(ExifDirectory? exifDirectory) =>
|
||||
MetaBase.GetOrientation(exifDirectory?.ExifBaseDirectories);
|
||||
|
||||
public static int? GetWidth(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||
MetaBase.GetWidth(exifBaseDirectories);
|
||||
|
||||
public static int? GetHeight(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||
MetaBase.GetHeight(exifBaseDirectories);
|
||||
|
||||
public static string? GetMaker(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||
MetaBase.GetMaker(exifBaseDirectories);
|
||||
|
||||
public static string? GetModel(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||
MetaBase.GetModel(exifBaseDirectories);
|
||||
|
||||
public static DateTime? GetDateTime(string dateTimeFormat, string? value) =>
|
||||
MetaBase.GetDateTime(dateTimeFormat, value);
|
||||
|
||||
public static int? GetOrientation(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||
MetaBase.GetOrientation(exifBaseDirectories);
|
||||
|
||||
public static ReadOnlyCollection<string> GetKeywords(ExifDirectory? exifDirectory) =>
|
||||
MetaBase.GetKeywords(exifDirectory?.ExifBaseDirectories);
|
||||
|
||||
public static ReadOnlyCollection<string> GetKeywords(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||
MetaBase.GetKeywords(exifBaseDirectories);
|
||||
|
||||
internal string TestStatic_DateTimeFormat() =>
|
||||
DateTimeFormat();
|
||||
|
||||
internal string? TestStatic_GetMaker(ExifDirectory? exifDirectory) =>
|
||||
GetMaker(exifDirectory);
|
||||
|
||||
internal string? TestStatic_GetModel(ExifDirectory? exifDirectory) =>
|
||||
GetModel(exifDirectory);
|
||||
|
||||
internal static int? TestStatic_GetWidth(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||
GetWidth(exifBaseDirectories);
|
||||
|
||||
internal static int? TestStatic_GetHeight(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||
GetHeight(exifBaseDirectories);
|
||||
|
||||
internal static string? TestStatic_GetMaker(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||
GetMaker(exifBaseDirectories);
|
||||
|
||||
internal static string? TestStatic_GetModel(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||
GetModel(exifBaseDirectories);
|
||||
|
||||
internal static DateTime? TestStatic_GetDateTime(string dateTimeFormat, string? value) =>
|
||||
GetDateTime(dateTimeFormat, value);
|
||||
|
||||
internal static int? TestStatic_GetOrientation(ExifDirectoryBase[]? exifBaseDirectories) =>
|
||||
GetOrientation(exifBaseDirectories);
|
||||
|
||||
|
@ -45,10 +45,10 @@ internal abstract class Id
|
||||
}
|
||||
|
||||
internal static byte GetHasDateTimeOriginal(Properties.IPropertyConfiguration propertyConfiguration, FilePath filePath) =>
|
||||
(byte)(!propertyConfiguration.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? filePath.Id > -1 ? 9 : 1 : filePath.Id > -1 ? 6 : 4);
|
||||
(byte)(propertyConfiguration.IgnoreExtensions.Contains(filePath.ExtensionLowered) || propertyConfiguration.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? filePath.Id > -1 ? 6 : 4 : filePath.Id > -1 ? 9 : 1);
|
||||
|
||||
internal static byte GetMissingDateTimeOriginal(Properties.IPropertyConfiguration propertyConfiguration, FilePath filePath) =>
|
||||
(byte)(!propertyConfiguration.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? filePath.Id > -1 ? 7 : 3 : filePath.Id > -1 ? 5 : 0);
|
||||
(byte)(propertyConfiguration.IgnoreExtensions.Contains(filePath.ExtensionLowered) || propertyConfiguration.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? filePath.Id > -1 ? 5 : 0 : filePath.Id > -1 ? 7 : 3);
|
||||
|
||||
internal static bool NameWithoutExtensionIsIdFormat(Properties.IPropertyConfiguration propertyConfiguration, string fileNameWithoutExtension)
|
||||
{
|
||||
|
@ -1,132 +0,0 @@
|
||||
using System.Drawing;
|
||||
|
||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
internal abstract class ImageHelper
|
||||
{
|
||||
|
||||
private static bool StartsWith(byte[] thisBytes, byte[] thatBytes)
|
||||
{
|
||||
for (int i = 0; i < thatBytes.Length; i += 1)
|
||||
{
|
||||
if (thisBytes[i] != thatBytes[i])
|
||||
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);
|
||||
}
|
||||
_ = binaryReader.ReadBytes(chunkLength - 2);
|
||||
}
|
||||
throw new ArgumentException("Could not recognize image format.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dimensions of an image.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the image to get the dimensions of.</param>
|
||||
/// <returns>The dimensions of the specified image.</returns>
|
||||
/// <exception cref="ArgumentException">The image was of an unrecognized format.</exception>
|
||||
internal static Size GetDimensions(BinaryReader binaryReader, int? faceRight, int? faceBottom)
|
||||
{
|
||||
Size? result = null;
|
||||
#pragma warning disable IDE0230
|
||||
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 },
|
||||
};
|
||||
#pragma warning restore IDE0230
|
||||
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))
|
||||
continue;
|
||||
result = kvPair.Value(binaryReader);
|
||||
break;
|
||||
}
|
||||
if (result is not null)
|
||||
break;
|
||||
}
|
||||
if (result is null)
|
||||
{
|
||||
if (faceRight is null || faceBottom is null)
|
||||
throw new Exception("face is null!");
|
||||
result = new(faceRight.Value, faceBottom.Value);
|
||||
}
|
||||
return result.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dimensions of an image.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the image to get the dimensions of.</param>
|
||||
/// <returns>The dimensions of the specified image.</returns>
|
||||
/// <exception cref="ArgumentException">The image was of an unrecognized format.</exception>
|
||||
internal static Size GetDimensions(string path, int? faceRight, int? faceBottom)
|
||||
{
|
||||
Size result;
|
||||
using BinaryReader binaryReader = new(File.OpenRead(path));
|
||||
result = GetDimensions(binaryReader, faceRight, faceBottom);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
|
||||
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
|
||||
@ -80,4 +81,55 @@ internal static class MetaBase
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
internal static int? GetWidth(ExifDirectoryBase[]? exifBaseDirectories)
|
||||
{
|
||||
int? result = null;
|
||||
// public const int TagImageWidth = 256;
|
||||
if (exifBaseDirectories is not null)
|
||||
{
|
||||
foreach (ExifDirectoryBase exifDirectoryBase in exifBaseDirectories)
|
||||
{
|
||||
result = exifDirectoryBase?.ImageWidthValue;
|
||||
if (result is not null)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static int? GetHeight(ExifDirectoryBase[]? exifBaseDirectories)
|
||||
{
|
||||
int? result = null;
|
||||
// public const int TagImageHeight = 257;
|
||||
if (exifBaseDirectories is not null)
|
||||
{
|
||||
foreach (ExifDirectoryBase exifDirectoryBase in exifBaseDirectories)
|
||||
{
|
||||
result = exifDirectoryBase?.ImageHeightValue;
|
||||
if (result is not null)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma warning disable CA1416
|
||||
|
||||
internal static DateTime? GetDateTime(string dateTimeFormat, string? value)
|
||||
{
|
||||
DateTime? result;
|
||||
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;
|
||||
}
|
||||
|
||||
#pragma warning restore CA1416
|
||||
|
||||
}
|
@ -40,8 +40,8 @@ internal abstract class XDate
|
||||
}
|
||||
if (results.Count == 0)
|
||||
{
|
||||
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(exifDirectory.FilePath.Name);
|
||||
DateTime? dateTime = GetDateTimeFromName(fileNameWithoutExtension);
|
||||
string? fileNameWithoutExtension = exifDirectory.FilePath is null ? null : Path.GetFileNameWithoutExtension(exifDirectory.FilePath.Name);
|
||||
DateTime? dateTime = fileNameWithoutExtension is null ? null : GetDateTimeFromName(fileNameWithoutExtension);
|
||||
if (dateTime is not null)
|
||||
results.Add(dateTime.Value);
|
||||
foreach (ExifDirectoryBase exifDirectoryBase in exifDirectory.ExifBaseDirectories)
|
||||
|
@ -188,7 +188,7 @@ internal abstract partial class XDirectory
|
||||
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
||||
filePaths.Add(filePath);
|
||||
}
|
||||
results.Add(new(filePaths));
|
||||
results.Add(filePaths.AsReadOnly());
|
||||
}
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
@ -201,14 +201,14 @@ internal abstract partial class XDirectory
|
||||
return results;
|
||||
}
|
||||
|
||||
internal static List<Models.FilePair> GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<int, List<FilePath>> fileNamesToFiles, IReadOnlyDictionary<int, List<FilePath>> compareFileNamesToFiles)
|
||||
internal static List<Models.FilePair> GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, IReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> fileNamesToFiles, IReadOnlyDictionary<int, ReadOnlyCollection<FilePath>> compareFileNamesToFiles)
|
||||
{
|
||||
List<Models.FilePair> results = [];
|
||||
FilePath? match;
|
||||
bool uniqueFileName;
|
||||
List<FilePath>? collection;
|
||||
Models.FilePair filePair;
|
||||
bool? isNotUniqueAndNeedsReview;
|
||||
ReadOnlyCollection<FilePath>? collection;
|
||||
foreach (ReadOnlyCollection<FilePath> filePaths in filePathsCollection)
|
||||
{
|
||||
foreach (FilePath filePath in filePaths)
|
||||
@ -227,7 +227,7 @@ internal abstract partial class XDirectory
|
||||
filePair = new(FilePath: filePath,
|
||||
IsUnique: uniqueFileName,
|
||||
IsNotUniqueAndNeedsReview: isNotUniqueAndNeedsReview,
|
||||
Collection: [],
|
||||
Collection: new([]),
|
||||
Match: null);
|
||||
else
|
||||
{
|
||||
@ -259,7 +259,7 @@ internal abstract partial class XDirectory
|
||||
return results;
|
||||
}
|
||||
|
||||
private static bool GetIsNotUniqueAndNeedsReview(FilePath filePath, List<FilePath> collection)
|
||||
private static bool GetIsNotUniqueAndNeedsReview(FilePath filePath, ReadOnlyCollection<FilePath> collection)
|
||||
{
|
||||
bool result = false;
|
||||
long max;
|
||||
@ -280,7 +280,7 @@ internal abstract partial class XDirectory
|
||||
return result;
|
||||
}
|
||||
|
||||
private static FilePath? GetMatch(FilePath filePath, List<FilePath> collection)
|
||||
private static FilePath? GetMatch(FilePath filePath, ReadOnlyCollection<FilePath> collection)
|
||||
{
|
||||
FilePath? result = null;
|
||||
List<long> lengths = [];
|
||||
@ -299,7 +299,7 @@ internal abstract partial class XDirectory
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<byte, ReadOnlyCollection<string>> fileGroups, Dictionary<int, ExifDirectory>? exifDirectoriesById, Action? tick)
|
||||
internal static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<byte, ReadOnlyCollection<string>> fileGroups, ReadOnlyDictionary<int, ExifDirectory>? exifDirectoriesById, Action? tick)
|
||||
{
|
||||
List<(FilePath, string)> results = [];
|
||||
string paddedId;
|
||||
|
@ -446,7 +446,7 @@ internal abstract class XPath
|
||||
{
|
||||
Dictionary<byte, ReadOnlyCollection<string>> results = [];
|
||||
foreach (KeyValuePair<byte, List<string>> keyValuePair in keyValuePairs)
|
||||
results.Add(keyValuePair.Key, new(keyValuePair.Value));
|
||||
results.Add(keyValuePair.Key, keyValuePair.Value.AsReadOnly());
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user