Removed Obsolete A_Property Methods
Changed GetDimensions to handle a stream at the end and one exit
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using View_by_Distance.Shared.Models;
|
||||
using View_by_Distance.Shared.Models.Properties;
|
||||
using View_by_Distance.Shared.Models.Stateless.Methods;
|
||||
@ -101,11 +102,11 @@ internal abstract class Container
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
(string aResultsFullGroupDirectory, _) = dlibDotNet.GetResultsFullGroupDirectories();
|
||||
string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
|
||||
if (!Directory.Exists(aPropertySingletonDirectory))
|
||||
_ = Directory.CreateDirectory(aPropertySingletonDirectory);
|
||||
List<FilePair> filePairs = GetFilePairs(dlibDotNet, propertyConfiguration, aPropertySingletonDirectory, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, exifDirectoriesById, directorySearchFilter);
|
||||
(_, string bResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories();
|
||||
string bMetadataSingletonDirectory = Path.Combine(bResultsFullGroupDirectory, propertyConfiguration.ResultSingleton);
|
||||
if (!Directory.Exists(bMetadataSingletonDirectory))
|
||||
_ = Directory.CreateDirectory(bMetadataSingletonDirectory);
|
||||
List<FilePair> filePairs = GetFilePairs(dlibDotNet, propertyConfiguration, bMetadataSingletonDirectory, filesCollectionDirectory, keyValuePairs, splatNineIdentifiers, filePathsCollection, exifDirectoriesById, directorySearchFilter);
|
||||
foreach (FilePair filePair in filePairs)
|
||||
{
|
||||
if (!directoryToItems.TryGetValue(filePair.FilePath.DirectoryFullPath, out items))
|
||||
@ -126,12 +127,12 @@ internal abstract class Container
|
||||
return (filePairs.Count, results.ToArray());
|
||||
}
|
||||
|
||||
private static List<FilePair> GetFilePairs(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory>? exifDirectoriesById, string directorySearchFilter)
|
||||
private static List<FilePair> GetFilePairs(IDlibDotNet dlibDotNet, IPropertyConfiguration propertyConfiguration, string bMetadataSingletonDirectory, string filesCollectionDirectory, ReadOnlyDictionary<int, ReadOnlyCollection<FilePath>>? keyValuePairs, ReadOnlyDictionary<int, Identifier>? splatNineIdentifiers, ReadOnlyCollection<ReadOnlyCollection<FilePath>> filePathsCollection, ReadOnlyDictionary<int, ExifDirectory>? exifDirectoriesById, string directorySearchFilter)
|
||||
{
|
||||
List<FilePair> results = [];
|
||||
const string extension = ".json";
|
||||
ReadOnlyCollection<Shared.Models.FilePair> filePairs;
|
||||
string jsonGroupDirectory = aPropertySingletonDirectory;
|
||||
string jsonGroupDirectory = bMetadataSingletonDirectory;
|
||||
int maxDegreeOfParallelism = Environment.ProcessorCount;
|
||||
int filesCollectionDirectoryLength = filesCollectionDirectory.Length;
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||
@ -208,7 +209,14 @@ internal abstract class Container
|
||||
string jsonFileName = $"{fileName}{extension}";
|
||||
string fullFileName = Path.Combine(directory, jsonFileName);
|
||||
MoveIf(jsonFileName, cei, directory, fullFileName);
|
||||
sourceDirectoryFileHolder = IFileHolder.Get(fullFileName);
|
||||
FileInfo fileInfo = new(fullFileName);
|
||||
if (exifDirectory is not null && !fileInfo.Exists)
|
||||
{
|
||||
string json = JsonSerializer.Serialize(exifDirectory, ExifDirectorySourceGenerationContext.Default.ExifDirectory);
|
||||
_ = Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
||||
fileInfo.Refresh();
|
||||
}
|
||||
sourceDirectoryFileHolder = IFileHolder.Get(fileInfo);
|
||||
}
|
||||
if (sourceDirectoryFileHolder.CreationTime is not null && sourceDirectoryFileHolder.LastWriteTime is not null && filePair.FilePath.LastWriteTicks != sourceDirectoryFileHolder.CreationTime.Value.Ticks)
|
||||
{
|
||||
|
@ -196,7 +196,9 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
||||
string[] changesFrom = [nameof(A_Property)];
|
||||
List<Tuple<string, DateTime>> subFileTuples = [];
|
||||
FileHolder resizedFileHolder = _Resize.GetResizedFileHolder(cResultsFullGroupDirectory, item, outputResolutionHasNumber);
|
||||
if (item.ExifDirectory is null || item.ExifDirectory.FilePath.Id is null || !item.SourceDirectoryFileHolder.Exists || item.SourceDirectoryFileHolder.CreationTime is null || item.SourceDirectoryFileHolder.LastWriteTime is null || item.Any())
|
||||
if (item.ExifDirectory is null || item.ExifDirectory.FilePath.Id is null)
|
||||
throw new Exception();
|
||||
if (!item.SourceDirectoryFileHolder.Exists || item.SourceDirectoryFileHolder.CreationTime is null || item.SourceDirectoryFileHolder.LastWriteTime is null || item.Any())
|
||||
throw new Exception();
|
||||
if (_Configuration.PropertyConfiguration.ForcePropertyLastWriteTimeToCreationTime && item.SourceDirectoryFileHolder.LastWriteTime.Value != item.SourceDirectoryFileHolder.CreationTime.Value)
|
||||
{
|
||||
@ -607,7 +609,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
||||
{
|
||||
ExifDirectory? result;
|
||||
if (filePair.Match is null)
|
||||
result = null;
|
||||
result = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(filePair.FilePath);
|
||||
else
|
||||
{
|
||||
string json = File.ReadAllText(filePair.Match.FullName);
|
||||
@ -1087,7 +1089,6 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
||||
const string directorySearchFilter = "*";
|
||||
bool configurationOutputResolutionsHas = false;
|
||||
ReadOnlyDictionary<long, List<int>> personKeyToIds;
|
||||
(int season, string seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear);
|
||||
string[] checkDirectories =
|
||||
[
|
||||
Path.Combine(_Configuration.PropertyConfiguration.RootDirectory, "Ancestry"),
|
||||
@ -1096,6 +1097,7 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
||||
];
|
||||
bool runToDoCollectionFirst = GetRunToDoCollectionFirst(_Configuration, ticks, checkDirectories);
|
||||
(aResultsFullGroupDirectory, bResultsFullGroupDirectory) = dlibDotNet.GetResultsFullGroupDirectories();
|
||||
(int season, string seasonName) = Shared.Models.Stateless.Methods.IProperty.GetSeason(dateTime.DayOfYear);
|
||||
Shared.Models.Stateless.Methods.IPath.ChangeDateForEmptyDirectories(_Configuration.PropertyConfiguration.RootDirectory, ticks);
|
||||
a2PeopleContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "([])");
|
||||
eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), _Configuration.PropertyConfiguration.ResultContent);
|
||||
@ -1145,27 +1147,22 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
||||
{
|
||||
if (outputResolution.Any(char.IsNumber))
|
||||
continue;
|
||||
Dictionary<int, ExifDirectory> exifDirectoriesById = [];
|
||||
bool filesCollectionCountIsOne = record?.FilesCollectionCountIsOne ?? false;
|
||||
(cResultsFullGroupDirectory, _, _, _) = dlibDotNet.GetResultsFullGroupDirectories(outputResolution);
|
||||
string? filesCollectionRootDirectory = Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent);
|
||||
ReadOnlyDictionary<int, ExifDirectory> exifDirectoriesById = record?.ExifDirectoriesById ?? new(new Dictionary<int, ExifDirectory>());
|
||||
string? filesCollectionRootDirectory = record?.FilesCollectionRootDirectory ?? Path.Combine(cResultsFullGroupDirectory, _Configuration.PropertyConfiguration.ResultContent);
|
||||
ReadOnlyCollection<ReadOnlyCollection<FilePath>>? filePathsCollection = IDirectory.GetFilePathCollections(_Configuration.PropertyConfiguration, directorySearchFilter, fileSearchFilter, filesCollectionRootDirectory, useIgnoreExtensions: true, useCeilingAverage: true);
|
||||
record = new(FilesCollectionRootDirectory: filesCollectionRootDirectory,
|
||||
FilesCollectionCountIsOne: false,
|
||||
FilesCollectionCountIsOne: filesCollectionCountIsOne,
|
||||
FilePathsCollection: filePathsCollection,
|
||||
ExifDirectoriesById: new(exifDirectoriesById),
|
||||
IdToFilePaths: null,
|
||||
SplatNineIdentifiers: null);
|
||||
ExifDirectoriesById: exifDirectoriesById,
|
||||
IdToFilePaths: record?.IdToFilePaths,
|
||||
SplatNineIdentifiers: record?.SplatNineIdentifiers);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(record?.FilesCollectionRootDirectory) || record.FilePathsCollection.Count == 0)
|
||||
throw new NullReferenceException(nameof(record.FilePathsCollection));
|
||||
foreach (string checkDirectory in checkDirectories)
|
||||
{
|
||||
seasonDirectory = Path.Combine(checkDirectory, $"{dateTime.Year}.{season} {seasonName} {Path.GetFileName(checkDirectory)}");
|
||||
if (!Directory.Exists(seasonDirectory))
|
||||
_ = Directory.CreateDirectory(seasonDirectory);
|
||||
}
|
||||
int count = record.FilePathsCollection.Select(l => l.Count).Sum();
|
||||
message = $") Building Container(s) - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
|
||||
_ProgressBar = new(count, message, _ProgressBarOptions);
|
||||
@ -1181,19 +1178,18 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
||||
record.FilePathsCollection,
|
||||
record.ExifDirectoriesById);
|
||||
_ProgressBar.Dispose();
|
||||
Verify(argZero, readOnlyContainers);
|
||||
foreach (string checkDirectory in checkDirectories)
|
||||
{
|
||||
seasonDirectory = Path.Combine(checkDirectory, $"{dateTime.Year}.{season} {seasonName} {Path.GetFileName(checkDirectory)}");
|
||||
if (!Directory.Exists(seasonDirectory))
|
||||
_ = Directory.CreateDirectory(seasonDirectory);
|
||||
}
|
||||
mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, _Distance, personContainers, ticks, a2PeopleContentDirectory, a2PeopleSingletonDirectory, eDistanceContentDirectory);
|
||||
DeleteContinueFiles(personContainers);
|
||||
if (!runToDoCollectionFirst)
|
||||
MapFaceFileLogic(ticks, personContainers, mapLogic, a2PeopleContentDirectory, eDistanceContentDirectory);
|
||||
FullDoWork(argZero,
|
||||
propertyRoot,
|
||||
ticks,
|
||||
fPhotoPrismSingletonDirectory,
|
||||
count,
|
||||
metadata,
|
||||
record,
|
||||
readOnlyContainers,
|
||||
mapLogic);
|
||||
FullDoWork(argZero, propertyRoot, ticks, fPhotoPrismSingletonDirectory, count, metadata, record, readOnlyContainers, mapLogic);
|
||||
ReadOnlyCollection<Item> distinctValidImageItems = Container.Models.Stateless.Methods.IContainer.GetValidImageItems(_Configuration.PropertyConfiguration, readOnlyContainers, distinctItems: true, filterItems: true);
|
||||
if (_Configuration.LookForAbandoned)
|
||||
{
|
||||
@ -1253,6 +1249,44 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
private void Verify(string argZero, ReadOnlyCollection<Container.Models.Container> readOnlyContainers)
|
||||
{
|
||||
int count = 0;
|
||||
List<Item> items = [];
|
||||
Container.Models.Container container;
|
||||
ReadOnlyCollection<Item> filteredItems;
|
||||
foreach (string outputResolution in _Configuration.OutputResolutions)
|
||||
{
|
||||
for (int i = 0; i < readOnlyContainers.Count; i++)
|
||||
{
|
||||
container = readOnlyContainers[i];
|
||||
if (container.Items.Count == 0)
|
||||
continue;
|
||||
if (!_ArgZeroIsConfigurationRootDirectory && !container.SourceDirectory.StartsWith(argZero))
|
||||
continue;
|
||||
filteredItems = Container.Models.Stateless.Methods.IContainer.GetValidImageItems(_Configuration.PropertyConfiguration, container);
|
||||
if (filteredItems.Count == 0)
|
||||
continue;
|
||||
foreach (Item item in filteredItems)
|
||||
{
|
||||
count++;
|
||||
if (item.ExifDirectory is null || item.ExifDirectory.FilePath.Id is null)
|
||||
{
|
||||
items.Add(item);
|
||||
continue;
|
||||
}
|
||||
if (!item.SourceDirectoryFileHolder.Exists || item.SourceDirectoryFileHolder.CreationTime is null || item.SourceDirectoryFileHolder.LastWriteTime is null || item.Any())
|
||||
{
|
||||
items.Add(item);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (items.Count > 0)
|
||||
throw new Exception($"{items.Count} item(s) of {count} item(s) are not setup!");
|
||||
}
|
||||
|
||||
private Record GetFilesCollectionThenCopyOrMove(IDlibDotNet dlibDotNet, long ticks, string fileSearchFilter, string directorySearchFilter, string bResultsFullGroupDirectory, string outputResolution)
|
||||
{
|
||||
Record result;
|
||||
@ -1279,6 +1313,8 @@ public partial class DlibDotNet : IDlibDotNet, IDisposable
|
||||
progressBar = new(count, message, _ProgressBarOptions);
|
||||
_ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) => ParallelFor(dlibDotNet, filePairs[i], exifDirectoriesById));
|
||||
progressBar.Dispose();
|
||||
if (exifDirectoriesById.Count == 0)
|
||||
throw new Exception("No exif directories were found!");
|
||||
count = filePathsCollection.Select(l => l.Count).Sum();
|
||||
bool filesCollectionCountIsOne = GetFilesCollectionCountIsOne(filePathsCollection);
|
||||
message = $") Selecting for ## pattern directory - {(int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds)} total second(s)";
|
||||
|
@ -8,18 +8,18 @@ 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 },
|
||||
{ new byte[] { 0xff, 0xd8 }, DecodeJfif },
|
||||
{ new byte[] { 0x52, 0x49, 0x46, 0x46 }, DecodeWebP },
|
||||
};
|
||||
#pragma warning restore IDE0230
|
||||
|
||||
private static bool StartsWith(byte[] thisBytes, byte[] thatBytes)
|
||||
private static bool StartsWith(List<byte> thisBytes, byte[] thatBytes)
|
||||
{
|
||||
for (int i = 0; i < thatBytes.Length; i += 1)
|
||||
for (int i = 0; i < thisBytes.Count && i < thatBytes.Length; i += 1)
|
||||
{
|
||||
if (thisBytes[i] == thatBytes[i])
|
||||
continue;
|
||||
@ -103,24 +103,41 @@ internal static class Dimensions
|
||||
|
||||
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)
|
||||
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
|
||||
{
|
||||
magicBytes[i] = binaryReader.ReadByte();
|
||||
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))
|
||||
return kvPair.Value(binaryReader);
|
||||
{
|
||||
result = kvPair.Value(binaryReader);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
if (result is not null)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static Size? GetDimensions(string path)
|
||||
{
|
||||
using BinaryReader binaryReader = new(File.OpenRead(path));
|
||||
return GetDimensions(binaryReader);
|
||||
Size? result;
|
||||
using FileStream fileStream = File.OpenRead(path);
|
||||
using BinaryReader binaryReader = new(fileStream);
|
||||
result = GetDimensions(binaryReader);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
using ShellProgressBar;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
@ -66,40 +65,6 @@ public class A_Property
|
||||
converted: false));
|
||||
}
|
||||
|
||||
[Obsolete("Use ExifDirectory")]
|
||||
public void SavePropertyParallelWork(long ticks, Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, int t, Container.Models.Container[] containers)
|
||||
{
|
||||
int total = 0;
|
||||
string message;
|
||||
int totalSeconds;
|
||||
bool anyNullOrNoIsUniqueFileName;
|
||||
List<Exception> exceptions = [];
|
||||
Container.Models.Container container;
|
||||
int containersLength = containers.Length;
|
||||
const string outputResolution = "Original";
|
||||
List<Tuple<string, DateTime>> sourceDirectoryChanges = [];
|
||||
string propertyRoot = IResult.GetResultsGroupDirectory(_PropertyConfiguration, nameof(A_Property));
|
||||
for (int i = 0; i < containers.Length; i++)
|
||||
{
|
||||
container = containers[i];
|
||||
if (container.Items.Count == 0)
|
||||
continue;
|
||||
sourceDirectoryChanges.Clear();
|
||||
if (container.Items.Count == 0)
|
||||
continue;
|
||||
anyNullOrNoIsUniqueFileName = container.Items.Any(l => !l.IsUniqueFileName);
|
||||
SetAngleBracketCollection(container.SourceDirectory, anyNullOrNoIsUniqueFileName);
|
||||
totalSeconds = (int)Math.Truncate(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
||||
message = $"{i + 1:000} [{container.Items.Count:000}] / {containersLength:000} - {total} / {t} total - {totalSeconds} total second(s) - {outputResolution} - {container.SourceDirectory}";
|
||||
SavePropertyParallelWork(_MaxDegreeOfParallelism, metadata, exceptions, sourceDirectoryChanges, container, container.Items, message);
|
||||
if (exceptions.Count == container.Items.Count)
|
||||
throw new Exception(string.Concat("All in [", container.SourceDirectory, "]failed!"));
|
||||
if (exceptions.Count != 0)
|
||||
_ExceptionsDirectories.Add(container.SourceDirectory);
|
||||
total += container.Items.Count;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetAngleBracketCollection(string sourceDirectory, bool anyNullOrNoIsUniqueFileName)
|
||||
{
|
||||
_AngleBracketCollection.Clear();
|
||||
@ -112,180 +77,6 @@ public class A_Property
|
||||
SetAngleBracketCollection(aResultsFullGroupDirectory, sourceDirectory, anyNullOrNoIsUniqueFileName);
|
||||
}
|
||||
|
||||
[Obsolete("Use ExifDirectory")]
|
||||
private void SavePropertyParallelWork(int maxDegreeOfParallelism, Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, List<Exception> exceptions, List<Tuple<string, DateTime>> sourceDirectoryChanges, Container.Models.Container container, ReadOnlyCollection<Item> items, string message)
|
||||
{
|
||||
List<Tuple<string, DateTime>> sourceDirectoryFileTuples = [];
|
||||
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
||||
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
||||
using ProgressBar progressBar = new(items.Count, message, options);
|
||||
_ = Parallel.For(0, items.Count, parallelOptions, (i, state) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
long ticks = DateTime.Now.Ticks;
|
||||
DateTime dateTime = DateTime.Now;
|
||||
List<Tuple<string, DateTime>> collection;
|
||||
SavePropertyParallelForWork(metadata, container.SourceDirectory, sourceDirectoryChanges, sourceDirectoryFileTuples, items[i]);
|
||||
if (i == 0 || sourceDirectoryChanges.Count != 0)
|
||||
progressBar.Tick();
|
||||
lock (sourceDirectoryFileTuples)
|
||||
collection = (from l in sourceDirectoryFileTuples where l.Item2 > dateTime select l).ToList();
|
||||
lock (sourceDirectoryChanges)
|
||||
sourceDirectoryChanges.AddRange(collection);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lock (exceptions)
|
||||
exceptions.Add(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Obsolete("Use ExifDirectory")]
|
||||
private void SavePropertyParallelForWork(Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, string sourceDirectory, List<Tuple<string, DateTime>> sourceDirectoryFileTuples, List<Tuple<string, DateTime>> sourceDirectoryChanges, Item item)
|
||||
{
|
||||
Shared.Models.Property property;
|
||||
List<string> parseExceptions = [];
|
||||
bool isIgnoreExtension = item.IsValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(item.FilePath.ExtensionLowered);
|
||||
string filteredSourceDirectoryFileExtensionLowered = Path.Combine(sourceDirectory, $"{item.FilePath.NameWithoutExtension}{item.FilePath.ExtensionLowered}");
|
||||
if (item.IsValidImageFormatExtension && item.FilePath.FullName.Length == filteredSourceDirectoryFileExtensionLowered.Length && item.FilePath.FullName != filteredSourceDirectoryFileExtensionLowered)
|
||||
File.Move(item.FilePath.FullName, filteredSourceDirectoryFileExtensionLowered);
|
||||
if (item.FileSizeChanged is null || item.FileSizeChanged.Value || item.LastWriteTimeChanged is null || item.LastWriteTimeChanged.Value || item.ExifDirectory is null)
|
||||
{
|
||||
property = GetImageProperty(metadata, item, sourceDirectoryFileTuples, parseExceptions, isIgnoreExtension);
|
||||
lock (sourceDirectoryChanges)
|
||||
sourceDirectoryChanges.Add(new Tuple<string, DateTime>(nameof(A_Property), DateTime.Now));
|
||||
lock (item)
|
||||
item.Update(null);
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use ExifDirectory")]
|
||||
private Shared.Models.Property GetImageProperty(Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, Item item, List<Tuple<string, DateTime>> sourceDirectoryFileTuples, List<string> parseExceptions, bool isIgnoreExtension)
|
||||
{
|
||||
Shared.Models.Property? result;
|
||||
int? id = null;
|
||||
FileInfo fileInfo;
|
||||
string? json = null;
|
||||
bool hasWrongYearProperty = false;
|
||||
string[] changesFrom = [];
|
||||
string angleBracket = _AngleBracketCollection[0];
|
||||
bool populateId = _Configuration.PopulatePropertyId;
|
||||
if (!item.IsUniqueFileName)
|
||||
fileInfo = new(Path.Combine(angleBracket.Replace("<>", _PropertyConfiguration.ResultSingleton), $"{item.FilePath.NameWithoutExtension}{item.FilePath.ExtensionLowered}.json"));
|
||||
else
|
||||
{
|
||||
string fileName = $"{item.FilePath.NameWithoutExtension}{item.FilePath.ExtensionLowered}.json";
|
||||
CombinedEnumAndIndex cei = Shared.Models.Stateless.Methods.IPath.GetCombinedEnumAndIndex(_PropertyConfiguration, item.FilePath);
|
||||
string directory = _ResultSingletonFileGroups[0][cei.Enum][cei.Index];
|
||||
fileInfo = new(Path.Combine(directory, fileName));
|
||||
MoveIf(fileName, cei, directory, fileInfo);
|
||||
}
|
||||
List<DateTime> dateTimes = (from l in sourceDirectoryFileTuples where l is not null && changesFrom.Contains(l.Item1) select l.Item2).ToList();
|
||||
if (_Configuration.ForcePropertyLastWriteTimeToCreationTime && !fileInfo.Exists && File.Exists(Path.ChangeExtension(fileInfo.FullName, ".delete")))
|
||||
{
|
||||
File.Move(Path.ChangeExtension(fileInfo.FullName, ".delete"), fileInfo.FullName);
|
||||
fileInfo.Refresh();
|
||||
}
|
||||
if (_Configuration.ForcePropertyLastWriteTimeToCreationTime && fileInfo.Exists && fileInfo.LastWriteTime != fileInfo.CreationTime)
|
||||
{
|
||||
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
|
||||
fileInfo.Refresh();
|
||||
}
|
||||
if (_Configuration.PropertiesChangedForProperty)
|
||||
result = null;
|
||||
else if (!fileInfo.Exists)
|
||||
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)
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
json = File.ReadAllText(fileInfo.FullName);
|
||||
try
|
||||
{
|
||||
if (item.ExifDirectory is not null)
|
||||
result = null;
|
||||
else
|
||||
result = JsonSerializer.Deserialize(json, PropertyGenerationContext.Default.Property);
|
||||
if (result is not null && json.Contains("WrongYear"))
|
||||
{
|
||||
id = result.Id;
|
||||
hasWrongYearProperty = true;
|
||||
result = null;
|
||||
}
|
||||
if (!isIgnoreExtension && item.IsValidImageFormatExtension && ((populateId && result?.Id is null) || result?.Width is null || result.Height is null))
|
||||
{
|
||||
id = result?.Id;
|
||||
result = null;
|
||||
}
|
||||
if (!isIgnoreExtension && item.IsValidImageFormatExtension && populateId && result is not null && result.LastWriteTime.Ticks != item.FilePath.LastWriteTicks)
|
||||
{
|
||||
id = null;
|
||||
result = null;
|
||||
}
|
||||
if (!isIgnoreExtension && item.IsValidImageFormatExtension && result?.Width is not null && result.Height is not null && result.Width.Value == result.Height.Value)
|
||||
{
|
||||
id = result.Id;
|
||||
result = null;
|
||||
if (result?.Width is not null && result.Height is not null && result.Width.Value != result.Height.Value)
|
||||
throw new Exception("Was square!");
|
||||
}
|
||||
if (!isIgnoreExtension && item.IsValidImageFormatExtension && result is not null && result.FileSize != item.FilePath.Length)
|
||||
{
|
||||
id = result.Id;
|
||||
result = null;
|
||||
}
|
||||
if (result is not null)
|
||||
{
|
||||
sourceDirectoryFileTuples.Add(new Tuple<string, DateTime>(nameof(A_Property), fileInfo.LastWriteTime));
|
||||
if (fileInfo.CreationTime != result.LastWriteTime)
|
||||
{
|
||||
File.SetCreationTime(fileInfo.FullName, result.LastWriteTime);
|
||||
File.SetLastWriteTime(fileInfo.FullName, fileInfo.LastWriteTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
result = null;
|
||||
parseExceptions.Add(nameof(A_Property));
|
||||
}
|
||||
}
|
||||
if (result is null)
|
||||
{
|
||||
id ??= item.FilePath.Id;
|
||||
(_, _, result) = Stateless.Property.GetProperty(populateId, metadata, item.FilePath, result, isIgnoreExtension, item.IsValidImageFormatExtension, id, _ASCIIEncoding);
|
||||
json = JsonSerializer.Serialize(result, PropertyGenerationContext.Default.Property);
|
||||
if (populateId && Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true))
|
||||
{
|
||||
File.SetCreationTime(fileInfo.FullName, result.LastWriteTime);
|
||||
if (!_Configuration.ForcePropertyLastWriteTimeToCreationTime)
|
||||
sourceDirectoryFileTuples.Add(new Tuple<string, DateTime>(nameof(A_Property), DateTime.Now));
|
||||
else
|
||||
{
|
||||
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
|
||||
fileInfo.Refresh();
|
||||
sourceDirectoryFileTuples.Add(new Tuple<string, DateTime>(nameof(A_Property), fileInfo.CreationTime));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (hasWrongYearProperty)
|
||||
{
|
||||
json = JsonSerializer.Serialize(result, PropertyGenerationContext.Default.Property);
|
||||
if (Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true))
|
||||
{
|
||||
File.SetCreationTime(fileInfo.FullName, result.LastWriteTime);
|
||||
File.SetLastWriteTime(fileInfo.FullName, fileInfo.CreationTime);
|
||||
fileInfo.Refresh();
|
||||
sourceDirectoryFileTuples.Add(new Tuple<string, DateTime>(nameof(A_Property), fileInfo.CreationTime));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, FileInfo fileInfo)
|
||||
{
|
||||
string[] segments = directory.Split(cei.Combined);
|
||||
@ -305,22 +96,4 @@ public class A_Property
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use ExifDirectory")]
|
||||
public Shared.Models.Property GetProperty(Shared.Models.Methods.IMetadata<MetadataExtractor.Directory> metadata, Item item, List<Tuple<string, DateTime>> sourceDirectoryFileTuples, List<string> parseExceptions)
|
||||
{
|
||||
Shared.Models.Property result;
|
||||
bool angleBracketCollectionAny = _AngleBracketCollection.Count != 0;
|
||||
if (!angleBracketCollectionAny)
|
||||
{
|
||||
if (item.FilePath.DirectoryFullPath is null)
|
||||
throw new NullReferenceException(nameof(item.FilePath.DirectoryFullPath));
|
||||
SetAngleBracketCollection(item.FilePath.DirectoryFullPath, !item.IsUniqueFileName);
|
||||
}
|
||||
bool isIgnoreExtension = item.IsValidImageFormatExtension && _PropertyConfiguration.IgnoreExtensions.Contains(item.FilePath.ExtensionLowered);
|
||||
result = GetImageProperty(metadata, item, sourceDirectoryFileTuples, parseExceptions, isIgnoreExtension);
|
||||
if (!angleBracketCollectionAny)
|
||||
_AngleBracketCollection.Clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -76,7 +76,7 @@ public class FaceFileSystem : FileSystem, Properties.IFaceFileSystem
|
||||
}
|
||||
else
|
||||
{
|
||||
System.Drawing.Size size = Stateless.Methods.ImageHelper.GetDimensions(fileInfo.FullName, faceRight, faceBottom);
|
||||
System.Drawing.Size size = Stateless.Methods.Dimensions.GetDimensions(fileInfo.FullName, faceRight, faceBottom);
|
||||
imageWidth = size.Width;
|
||||
imageHeight = size.Height;
|
||||
}
|
||||
|
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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user