AddUserSecrets, RenameByDateTaken and BlurHash

This commit is contained in:
Mike Phares 2023-05-21 18:11:26 -07:00
parent aec9d0a55d
commit 514637b9c6
70 changed files with 1128 additions and 193 deletions

View File

@ -16,6 +16,7 @@
"Exif", "Exif",
"Getα", "Getα",
"Greyscale", "Greyscale",
"Hasher",
"jfif", "jfif",
"mmod", "mmod",
"Nicéphore", "Nicéphore",

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1,4 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("BlurHash.Core.Test")]
[assembly: InternalsVisibleTo("Benchmarks")]

64
BlurHash.Core/Base83.cs Normal file
View File

@ -0,0 +1,64 @@
namespace BlurHash;
/// <summary>
/// Contains methods to encode or decode integers to Base83-Strings
/// </summary>
internal static class Base83
{
internal const string _Charset = @"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~";
private static readonly IReadOnlyDictionary<char, int> _ReverseLookup;
static Base83()
{
// Build inverse lookup table for fast decoding
Dictionary<char, int> charIndices = new();
int index = 0;
foreach (char c in _Charset)
{
charIndices[c] = index;
index++;
}
_ReverseLookup = charIndices;
}
/// <summary>
/// Encodes a number into its Base83-representation
/// </summary>
/// <param name="number">The number to encode</param>
/// <param name="output">The data buffer to put the result data into</param>
/// <returns>The Base83-representation of the number</returns>
public static void EncodeBase83(this int number, Span<char> output)
{
int length = output.Length;
for (int i = 0; i < length; i++)
{
int digit = number % 83;
number /= 83;
output[length - i - 1] = _Charset[digit];
}
}
/// <summary>
/// Decodes an <code>IEnumerable</code> of Base83-characters into the integral value it represents
/// </summary>
/// <param name="base83Data">The characters to decode</param>
/// <returns>The decoded value as integer</returns>
public static int DecodeBase83(this ReadOnlySpan<char> base83Data)
{
int result = 0;
foreach (char c in base83Data)
{
if (!_ReverseLookup.TryGetValue(c, out int digit))
{
throw new ArgumentException("The given string contains invalid characters.", nameof(base83Data));
}
result *= 83;
result += digit;
}
return result;
}
}

View File

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>10.0</LangVersion>
<Nullable>enable</Nullable>
<OutputType>library</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<PackageId>BlurHash.Core</PackageId>
<PackageVersion>2.0.0</PackageVersion>
<Authors>Markus Palcer</Authors>
<Description>BlurHash is a compact representation of a placeholder for an image.</Description>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<Copyright>Copyright 2019 Markus Palcer</Copyright>
<PackageTags>blurhash image preview compression encoding</PackageTags>
<PackageProjectUrl>https://github.com/MarkusPalcer/blurhash.net</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.5" />
</ItemGroup>
</Project>

267
BlurHash.Core/Core.cs Normal file
View File

@ -0,0 +1,267 @@
using System.Numerics;
namespace BlurHash;
public static class Core
{
/// <summary>
/// Encodes a 2-dimensional array of pixels into a BlurHash string
/// </summary>
/// <param name="pixels">The 2-dimensional array of pixels to encode</param>
/// <param name="componentsX">The number of components used on the X-Axis for the DCT</param>
/// <param name="componentsY">The number of components used on the Y-Axis for the DCT</param>
/// <param name="progressCallback">An optional progress handler to receive progress updates</param>
/// <returns>The resulting BlurHash string</returns>
public static string Encode(Pixel[,] pixels, int componentsX, int componentsY, IProgress<int>? progressCallback = null)
{
if (componentsX < 1)
throw new ArgumentException("componentsX needs to be at least 1");
if (componentsX > 9)
throw new ArgumentException("componentsX needs to be at most 9");
if (componentsY < 1)
throw new ArgumentException("componentsY needs to be at least 1");
if (componentsY > 9)
throw new ArgumentException("componentsY needs to be at most 9");
Span<Pixel> factors = stackalloc Pixel[componentsX * componentsY];
Span<char> resultBuffer = stackalloc char[4 + 2 * componentsX * componentsY];
int factorCount = componentsX * componentsY;
int processedFactors = 0;
int width = pixels.GetLength(0);
int height = pixels.GetLength(1);
double[] xCosines = new double[width];
double[] yCosines = new double[height];
for (int yComponent = 0; yComponent < componentsY; yComponent++)
for (int xComponent = 0; xComponent < componentsX; xComponent++)
{
double r = 0, g = 0, b = 0;
double normalization = (xComponent == 0 && yComponent == 0) ? 1 : 2;
for (int xPixel = 0; xPixel < width; xPixel++)
{
xCosines[xPixel] = Math.Cos(Math.PI * xComponent * xPixel / width);
}
for (int yPixel = 0; yPixel < height; yPixel++)
{
yCosines[yPixel] = Math.Cos(Math.PI * yComponent * yPixel / height);
}
for (int xPixel = 0; xPixel < width; xPixel++)
for (int yPixel = 0; yPixel < height; yPixel++)
{
double basis = xCosines[xPixel] * yCosines[yPixel];
Pixel pixel = pixels[xPixel, yPixel];
r += basis * pixel._Red;
g += basis * pixel._Green;
b += basis * pixel._Blue;
}
double scale = normalization / (width * height);
factors[componentsX * yComponent + xComponent]._Red = r * scale;
factors[componentsX * yComponent + xComponent]._Green = g * scale;
factors[componentsX * yComponent + xComponent]._Blue = b * scale;
progressCallback?.Report(processedFactors * 100 / factorCount);
processedFactors++;
}
Pixel dc = factors[0];
int acCount = componentsX * componentsY - 1;
int sizeFlag = componentsX - 1 + (componentsY - 1) * 9;
sizeFlag.EncodeBase83(resultBuffer[..1]);
float maximumValue;
if (acCount > 0)
{
// Get maximum absolute value of all AC components
double actualMaximumValue = 0.0;
for (int yComponent = 0; yComponent < componentsY; yComponent++)
for (int xComponent = 0; xComponent < componentsX; xComponent++)
{
// Ignore DC component
if (xComponent == 0 && yComponent == 0)
continue;
int factorIndex = componentsX * yComponent + xComponent;
actualMaximumValue = Math.Max(Math.Abs(factors[factorIndex]._Red), actualMaximumValue);
actualMaximumValue = Math.Max(Math.Abs(factors[factorIndex]._Green), actualMaximumValue);
actualMaximumValue = Math.Max(Math.Abs(factors[factorIndex]._Blue), actualMaximumValue);
}
int quantizedMaximumValue = (int)Math.Max(0.0, Math.Min(82.0, Math.Floor(actualMaximumValue * 166 - 0.5)));
maximumValue = ((float)quantizedMaximumValue + 1) / 166;
quantizedMaximumValue.EncodeBase83(resultBuffer.Slice(1, 1));
}
else
{
maximumValue = 1;
resultBuffer[1] = '0';
}
EncodeDc(dc._Red, dc._Green, dc._Blue).EncodeBase83(resultBuffer.Slice(2, 4));
for (int yComponent = 0; yComponent < componentsY; yComponent++)
for (int xComponent = 0; xComponent < componentsX; xComponent++)
{
// Ignore DC component
if (xComponent == 0 && yComponent == 0)
continue;
int factorIndex = componentsX * yComponent + xComponent;
EncodeAc(factors[factorIndex]._Red, factors[factorIndex]._Green, factors[factorIndex]._Blue, maximumValue).EncodeBase83(resultBuffer.Slice(6 + (factorIndex - 1) * 2, 2));
}
return resultBuffer.ToString();
}
/// <summary>
/// Decodes a BlurHash string into a 2-dimensional array of pixels
/// </summary>
/// <param name="blurhash">The blurhash string to decode</param>
/// <param name="pixels">
/// A two-dimensional array that will be filled with the pixel data.<br />
/// First dimension is the width, second dimension is the height
/// </param>
/// <param name="punch">A value that affects the contrast of the decoded image. 1 means normal, smaller values will make the effect more subtle, and larger values will make it stronger.</param>
/// <param name="progressCallback">An optional progress handler to receive progress updates</param>
/// <returns>A 2-dimensional array of <see cref="Pixel"/>s </returns>
public static void Decode(string blurhash, Pixel[,] pixels, double punch = 1.0, IProgress<int>? progressCallback = null)
{
if (blurhash.Length < 6)
{
throw new ArgumentException("BlurHash value needs to be at least 6 characters", nameof(blurhash));
}
ReadOnlySpan<char> blurhashSpan = blurhash.AsSpan();
int outputWidth = pixels.GetLength(0);
int outputHeight = pixels.GetLength(1);
int sizeFlag = blurhashSpan[..1].DecodeBase83();
int componentsY = sizeFlag / 9 + 1;
int componentsX = sizeFlag % 9 + 1;
int componentCount = componentsX * componentsY;
if (blurhash.Length != 4 + 2 * componentsX * componentsY)
{
throw new ArgumentException("BlurHash value is missing data", nameof(blurhash));
}
double quantizedMaximumValue = blurhashSpan.Slice(1, 1).DecodeBase83();
double maximumValue = (quantizedMaximumValue + 1.0) / 166.0;
Pixel[,] coefficients = new Pixel[componentsX, componentsY];
int componentIndex = 0;
for (int yComponent = 0; yComponent < componentsY; yComponent++)
for (int xComponent = 0; xComponent < componentsX; xComponent++)
{
if (xComponent == 0 && yComponent == 0)
{
int value = blurhashSpan.Slice(2, 4).DecodeBase83();
coefficients[xComponent, yComponent] = DecodeDc(value);
}
else
{
int value = blurhashSpan.Slice(4 + componentIndex * 2, 2).DecodeBase83();
coefficients[xComponent, yComponent] = DecodeAc(value, maximumValue * punch);
}
componentIndex++;
}
for (int xPixel = 0; xPixel < outputWidth; xPixel++)
for (int yPixel = 0; yPixel < outputHeight; yPixel++)
{
ref Pixel result = ref pixels[xPixel, yPixel];
result._Red = 0.0;
result._Green = 0.0;
result._Blue = 0.0;
}
double[] xCosines = new double[outputWidth];
double[] yCosines = new double[outputHeight];
componentIndex = 1;
for (int componentX = 0; componentX < componentsX; componentX++)
for (int componentY = 0; componentY < componentsY; componentY++)
{
for (int xPixel = 0; xPixel < outputWidth; xPixel++)
{
xCosines[xPixel] = Math.Cos(Math.PI * xPixel * componentX / outputWidth);
}
for (int yPixel = 0; yPixel < outputHeight; yPixel++)
{
yCosines[yPixel] = Math.Cos(Math.PI * yPixel * componentY / outputHeight);
}
Pixel coefficient = coefficients[componentX, componentY];
for (int xPixel = 0; xPixel < outputWidth; xPixel++)
for (int yPixel = 0; yPixel < outputHeight; yPixel++)
{
ref Pixel result = ref pixels[xPixel, yPixel];
double basis = xCosines[xPixel] * yCosines[yPixel];
result._Red += coefficient._Red * basis;
result._Green += coefficient._Green * basis;
result._Blue += coefficient._Blue * basis;
}
progressCallback?.Report(componentIndex * 100 / componentCount);
componentIndex++;
}
}
private static int EncodeAc(double r, double g, double b, double maximumValue)
{
int quantizedR = (int)Math.Max(0, Math.Min(18, Math.Floor(MathUtils.SignPow(r / maximumValue, 0.5) * 9 + 9.5)));
int quantizedG = (int)Math.Max(0, Math.Min(18, Math.Floor(MathUtils.SignPow(g / maximumValue, 0.5) * 9 + 9.5)));
int quantizedB = (int)Math.Max(0, Math.Min(18, Math.Floor(MathUtils.SignPow(b / maximumValue, 0.5) * 9 + 9.5)));
return quantizedR * 19 * 19 + quantizedG * 19 + quantizedB;
}
private static int EncodeDc(double r, double g, double b)
{
int roundedR = MathUtils.LinearTosRgb(r);
int roundedG = MathUtils.LinearTosRgb(g);
int roundedB = MathUtils.LinearTosRgb(b);
return (roundedR << 16) + (roundedG << 8) + roundedB;
}
private static Pixel DecodeDc(BigInteger value)
{
int intR = (int)value >> 16;
int intG = (int)(value >> 8) & 255;
int intB = (int)value & 255;
return new Pixel(MathUtils.SRgbToLinear(intR), MathUtils.SRgbToLinear(intG), MathUtils.SRgbToLinear(intB));
}
private static Pixel DecodeAc(BigInteger value, double maximumValue)
{
double quantizedR = (double)(value / (19 * 19));
double quantizedG = (double)(value / 19 % 19);
double quantizedB = (double)(value % 19);
Pixel result = new(
MathUtils.SignPow((quantizedR - 9.0) / 9.0, 2.0) * maximumValue,
MathUtils.SignPow((quantizedG - 9.0) / 9.0, 2.0) * maximumValue,
MathUtils.SignPow((quantizedB - 9.0) / 9.0, 2.0) * maximumValue
);
return result;
}
}

View File

@ -0,0 +1,38 @@
namespace BlurHash;
/// <summary>
/// Utility methods for mathematical calculations
/// </summary>
public static class MathUtils
{
/// <summary>
/// Calculates <c>Math.Pow(base, exponent)</c> but retains the sign of <c>base</c> in the result.
/// </summary>
/// <param name="base">The base of the power. The sign of this value will be the sign of the result</param>
/// <param name="exponent">The exponent of the power</param>
public static double SignPow(double @base, double exponent) => Math.Sign(@base) * Math.Pow(Math.Abs(@base), exponent);
/// <summary>
/// Converts an sRGB input value (0 to 255) into a linear double value
/// </summary>
public static double SRgbToLinear(int value)
{
double v = value / 255.0;
if (v <= 0.04045)
return v / 12.92;
else
return Math.Pow((v + 0.055) / 1.055, 2.4);
}
/// <summary>
/// Converts a linear double value into an sRGB input value (0 to 255)
/// </summary>
public static int LinearTosRgb(double value)
{
double v = Math.Max(0.0, Math.Min(1.0, value));
if (v <= 0.0031308)
return (int)(v * 12.92 * 255 + 0.5);
else
return (int)((1.055 * Math.Pow(v, 1 / 2.4) - 0.055) * 255 + 0.5);
}
}

18
BlurHash.Core/Pixel.cs Normal file
View File

@ -0,0 +1,18 @@
namespace BlurHash;
/// <summary>
/// Represents a pixel within the BlurHash algorithm
/// </summary>
public struct Pixel
{
public double _Red;
public double _Green;
public double _Blue;
public Pixel(double red, double green, double blue)
{
_Red = red;
_Green = green;
_Blue = blue;
}
}

View File

@ -0,0 +1 @@
[]

View File

@ -0,0 +1,4 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("BlurHash.System.Drawing.Common.Test")]
[assembly: InternalsVisibleTo("Benchmarks")]

View File

@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>10.0</LangVersion>
<Nullable>enable</Nullable>
<OutputType>library</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup>
<PackageId>BlurHash.System.Drawing.Common</PackageId>
<PackageVersion>3.0.0</PackageVersion>
<Authors>Markus Palcer</Authors>
<Description>BlurHash is a compact representation of a placeholder for an image.</Description>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<Copyright>Copyright 2019 Markus Palcer</Copyright>
<PackageTags>blurhash image preview compression encoding</PackageTags>
<PackageProjectUrl>https://github.com/MarkusPalcer/blurhash.net</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\BlurHash.Core\BlurHash.Core.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,110 @@
using BlurHash;
using System.Drawing.Imaging;
namespace System.Drawing.BlurHash;
public static class BlurHasher
{
#pragma warning disable CA1416
/// <summary>
/// Encodes a picture into a BlurHash string
/// </summary>
/// <param name="image">The picture to encode</param>
/// <param name="componentsX">The number of components used on the X-Axis for the DCT</param>
/// <param name="componentsY">The number of components used on the Y-Axis for the DCT</param>
/// <returns>The resulting BlurHash string</returns>
public static string Encode(Image image, int componentsX, int componentsY) => Core.Encode(ConvertBitmap(image as Bitmap ?? new Bitmap(image)), componentsX, componentsY);
/// <summary>
/// Decodes a BlurHash string into a <c>System.Drawing.Image</c>
/// </summary>
/// <param name="blurhash">The blurhash string to decode</param>
/// <param name="outputWidth">The desired width of the output in pixels</param>
/// <param name="outputHeight">The desired height of the output in pixels</param>
/// <param name="punch">A value that affects the contrast of the decoded image. 1 means normal, smaller values will make the effect more subtle, and larger values will make it stronger.</param>
/// <returns>The decoded preview</returns>
public static Image Decode(string blurhash, int outputWidth, int outputHeight, double punch = 1.0)
{
Pixel[,] pixelData = new Pixel[outputWidth, outputHeight];
Core.Decode(blurhash, pixelData, punch);
return ConvertToBitmap(pixelData);
}
/// <summary>
/// Converts the given bitmap to the library-independent representation used within the BlurHash-core
/// </summary>
/// <param name="sourceBitmap">The bitmap to encode</param>
public static unsafe Pixel[,] ConvertBitmap(Image sourceBitmap)
{
int width = sourceBitmap.Width;
int height = sourceBitmap.Height;
using Bitmap temporaryBitmap = new(width, height, PixelFormat.Format24bppRgb);
using (Graphics graphics = Graphics.FromImage(temporaryBitmap))
{
graphics.DrawImageUnscaled(sourceBitmap, 0, 0);
}
// Lock the bitmap's bits.
BitmapData bmpData = temporaryBitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, temporaryBitmap.PixelFormat);
// Get the address of the first line.
nint ptr = bmpData.Scan0;
Pixel[,] result = new Pixel[width, height];
byte* rgb = (byte*)ptr.ToPointer();
for (int y = 0; y < height; y++)
{
int index = bmpData.Stride * y;
for (int x = 0; x < width; x++)
{
ref Pixel res = ref result[x, y];
res._Blue = MathUtils.SRgbToLinear(rgb[index++]);
res._Green = MathUtils.SRgbToLinear(rgb[index++]);
res._Red = MathUtils.SRgbToLinear(rgb[index++]);
}
}
temporaryBitmap.UnlockBits(bmpData);
return result;
}
/// <summary>
/// Converts the library-independent representation of pixels into a bitmap
/// </summary>
/// <param name="pixelData">The library-independent representation of the image</param>
/// <returns>A <c>System.Drawing.Bitmap</c> in 32bpp-RGB representation</returns>
public static unsafe Bitmap ConvertToBitmap(Pixel[,] pixelData)
{
int width = pixelData.GetLength(0);
int height = pixelData.GetLength(1);
byte[] data = new byte[width * height * 4];
int index = 0;
for (int yPixel = 0; yPixel < height; yPixel++)
for (int xPixel = 0; xPixel < width; xPixel++)
{
Pixel pixel = pixelData[xPixel, yPixel];
data[index++] = (byte)MathUtils.LinearTosRgb(pixel._Blue);
data[index++] = (byte)MathUtils.LinearTosRgb(pixel._Green);
data[index++] = (byte)MathUtils.LinearTosRgb(pixel._Red);
data[index++] = 0;
}
Bitmap bmp;
fixed (byte* ptr = data)
{
bmp = new Bitmap(width, height, width * 4, PixelFormat.Format32bppRgb, new IntPtr(ptr));
}
return bmp;
}
}

45
BlurHash/BlurHash.csproj Normal file
View File

@ -0,0 +1,45 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>10.0</LangVersion>
<Nullable>enable</Nullable>
<OutputType>library</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<PackageId>Phares.View.by.Distance.BlurHash</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>7.0.101.1</Version>
<Authors>Mike Phares</Authors>
<Company>Phares</Company>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
<PropertyGroup>
<IsWindows Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))' == 'true'">true</IsWindows>
<IsOSX Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' == 'true'">true</IsOSX>
<IsLinux Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' == 'true'">true</IsLinux>
</PropertyGroup>
<PropertyGroup Condition="'$(IsWindows)'=='true'">
<DefineConstants>Windows</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(IsOSX)'=='true'">
<DefineConstants>OSX</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(IsLinux)'=='true'">
<DefineConstants>Linux</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'browser-wasm'">
<SupportedPlatform Include="browser" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
<PackageReference Include="System.Text.Json" Version="7.0.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
<ProjectReference Include="..\BlurHash.System.Drawing.Common\BlurHash.System.Drawing.Common.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,52 @@
using System.Drawing;
using System.Text;
using View_by_Distance.Shared.Models.Methods;
namespace View_by_Distance.BlurHash.Models;
public class BlurHasher : IBlurHasher
{
string IBlurHasher.Encode(Image image) =>
#pragma warning disable CA1416
image.Width < image.Height ? Encode(image, 4, 3) : Encode(image, 3, 4);
#pragma warning restore CA1416
string IBlurHasher.EncodeAndSave(Image image, string directory) =>
#pragma warning disable CA1416
image.Width < image.Height ? EncodeAndSave(image, 4, 3, 300, 190, directory) : EncodeAndSave(image, 3, 4, 300, 190, directory);
#pragma warning restore CA1416
string IBlurHasher.Encode(Image image, int x, int y) =>
Encode(image, x, y);
string IBlurHasher.EncodeAndSave(Image image, int x, int y, string directory) =>
EncodeAndSave(image, x, y, 300, 190, directory);
internal static string Encode(Image image, int x, int y) =>
System.Drawing.BlurHash.BlurHasher.Encode(image, x, y);
public string EncodeAndSave(Image image, int x, int y, int width, int height, string directory)
{
string result;
int actualByte;
result = System.Drawing.BlurHash.BlurHasher.Encode(image, x, y);
byte[] blurHashBytes = Encoding.UTF8.GetBytes(result);
using Bitmap actualImage = (Bitmap)System.Drawing.BlurHash.BlurHasher.Decode(result, width, height);
string joined = string.Join(string.Empty, blurHashBytes.Select(l => l.ToString("000")));
string fileName = Path.Combine(directory, $"{x}x{y}-{width}x{height}-{joined}.png");
if (!File.Exists(fileName))
{
using FileStream fileStream = new(fileName, FileMode.CreateNew);
#pragma warning disable CA1416
actualImage.Save(fileStream, System.Drawing.Imaging.ImageFormat.Png);
#pragma warning restore CA1416
_ = fileStream.Seek(0, SeekOrigin.Begin);
actualByte = fileStream.ReadByte();
while (actualByte > -1)
actualByte = fileStream.ReadByte();
}
return result;
}
}

View File

@ -38,7 +38,7 @@
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="7.0.5" /> <PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="7.0.5" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="7.0.5" /> <PackageReference Include="Microsoft.Extensions.Identity.Core" Version="7.0.5" />
<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" /> <PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />

View File

@ -19,7 +19,8 @@ public class Program
IsEnvironment isEnvironment = new(processesCount: null, nullASPNetCoreEnvironmentIsDevelopment: debuggerWasAttachedAtLineZero, nullASPNetCoreEnvironmentIsProduction: !debuggerWasAttachedAtLineZero); IsEnvironment isEnvironment = new(processesCount: null, nullASPNetCoreEnvironmentIsDevelopment: debuggerWasAttachedAtLineZero, nullASPNetCoreEnvironmentIsProduction: !debuggerWasAttachedAtLineZero);
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
.AddEnvironmentVariables() .AddEnvironmentVariables()
.AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true); .AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true)
.AddUserSecrets<Program>();
IConfigurationRoot configurationRoot = configurationBuilder.Build(); IConfigurationRoot configurationRoot = configurationBuilder.Build();
AppSettings appSettings = Models.Binder.AppSettings.Get(configurationRoot); AppSettings appSettings = Models.Binder.AppSettings.Get(configurationRoot);
if (appSettings.MaxDegreeOfParallelism > Environment.ProcessorCount) if (appSettings.MaxDegreeOfParallelism > Environment.ProcessorCount)

View File

@ -0,0 +1,16 @@
{
"_Application": "Date-Group",
"Windows": {
"Configuration": {
"xByHash": false,
"ByHash": true,
"xPopulatePropertyId": false,
"PopulatePropertyId": true,
"RootDirectory": "D:/Tmp/phares/Pictures",
"xxRootDirectory": "C:/Tmp/Phares/Compare/Images-1e85c0ba",
"xxxRootDirectory": "F:/Tmp/Phares/Compare/Not-Copy-Copy-1e85c0ba",
"xxxxRootDirectory": "C:/Tmp/Phares/Compare/Not-Copy-Copy-1e85c0ba",
"xxxxxRootDirectory": "F:/Tmp/Phares/2022-11-03-DCIM/DCIM/100D3400 2022"
}
}
}

View File

@ -1,38 +1,72 @@
{ {
"version": "2.0.0", "version": "2.0.0",
"options": {
"env": {
"serverUserSecretsId": "8004d966-1a9e-4545-a220-83f32b6a13e9"
}
},
"tasks": [ "tasks": [
{
"label": "userSecretsInit",
"command": "dotnet",
"type": "process",
"args": [
"user-secrets",
"-p",
"${workspaceFolder}/Date-Group.csproj",
"init"
],
"problemMatcher": "$msCompile"
},
{
"label": "userSecretsSet",
"command": "dotnet",
"type": "process",
"args": [
"user-secrets",
"-p",
"${workspaceFolder}/Date-Group.csproj",
"set",
"SaveDirectory",
"D:/1) Images A/Images-1e85c0ba-Results/A2) People/1e85c0ba/([])"
],
"problemMatcher": "$msCompile"
},
{
"label": "userSecretsMkLink",
"command": "cmd",
"type": "shell",
"args": [
"/c",
"mklink",
"/J",
".vscode\\UserSecrets",
"${userHome}\\AppData\\Roaming\\Microsoft\\UserSecrets\\$env:serverUserSecretsId"
],
"problemMatcher": "$msCompile"
},
{
"label": "format",
"command": "dotnet",
"type": "process",
"args": [
"format",
"--report",
".vscode",
"--verbosity",
"detailed",
"--severity",
"warn"
],
"problemMatcher": "$msCompile"
},
{ {
"label": "build", "label": "build",
"command": "dotnet", "command": "dotnet",
"type": "process", "type": "process",
"args": [ "args": [
"build", "build",
"${workspaceFolder}/Date-Group.csproj", "${workspaceFolder}/View-by-Distance-MKLink-Console.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/Date-Group.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"${workspaceFolder}/Date-Group.csproj",
"/property:GenerateFullPaths=true", "/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary" "/consoleloggerparameters:NoSummary"
], ],

View File

@ -6,7 +6,8 @@
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net7.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
</PropertyGroup> <UserSecretsId>8004d966-1a9e-4545-a220-83f32b6a13e9</UserSecretsId>
</PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.Date.Group</PackageId> <PackageId>Phares.View.by.Distance.Date.Group</PackageId>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
@ -38,8 +39,8 @@
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="7.0.5" /> <PackageReference Include="Microsoft.Extensions.Identity.Core" Version="7.0.5" />
<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" />
<PackageReference Include="MetadataExtractor" Version="2.7.2" /> <PackageReference Include="MetadataExtractor" Version="2.8.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" /> <PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />
@ -49,6 +50,7 @@
<PackageReference Include="System.Text.Json" Version="7.0.2" /> <PackageReference Include="System.Text.Json" Version="7.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\BlurHash\BlurHash.csproj" />
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" /> <ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
<ProjectReference Include="..\Property\Property.csproj" /> <ProjectReference Include="..\Property\Property.csproj" />
</ItemGroup> </ItemGroup>

View File

@ -65,7 +65,8 @@ public class DateGroup
throw new Exception(); throw new Exception();
if (propertyConfiguration.PopulatePropertyId && (configuration.ByCreateDateShortcut || configuration.ByHash) && Shared.Models.Stateless.Methods.IProperty.Any(containers)) if (propertyConfiguration.PopulatePropertyId && (configuration.ByCreateDateShortcut || configuration.ByHash) && Shared.Models.Stateless.Methods.IProperty.Any(containers))
{ {
propertyLogic.SavePropertyParallelWork(ticks, t, containers); IBlurHasher? blurHasher = new BlurHash.Models.BlurHasher();
propertyLogic.SavePropertyParallelWork(ticks, t, containers, blurHasher);
if (appSettings.MaxDegreeOfParallelism < 2) if (appSettings.MaxDegreeOfParallelism < 2)
ticks = LogDelta(ticks, nameof(A_Property.SavePropertyParallelWork)); ticks = LogDelta(ticks, nameof(A_Property.SavePropertyParallelWork));
if (propertyLogic.ExceptionsDirectories.Any()) if (propertyLogic.ExceptionsDirectories.Any())

View File

@ -20,7 +20,8 @@ public class Program
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
.AddEnvironmentVariables() .AddEnvironmentVariables()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true); .AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true)
.AddUserSecrets<Program>();
IConfigurationRoot configurationRoot = configurationBuilder.Build(); IConfigurationRoot configurationRoot = configurationBuilder.Build();
AppSettings appSettings = Models.Binder.AppSettings.Get(configurationRoot); AppSettings appSettings = Models.Binder.AppSettings.Get(configurationRoot);
if (appSettings.MaxDegreeOfParallelism > Environment.ProcessorCount) if (appSettings.MaxDegreeOfParallelism > Environment.ProcessorCount)

View File

@ -4,22 +4,7 @@
"Log4netProvider": "Debug" "Log4netProvider": "Debug"
} }
}, },
"MaxDegreeOfParallelism": 6,
"Serilog": { "Serilog": {
"MinimumLevel": "Debug" "MinimumLevel": "Debug"
},
"Windows": {
"Configuration": {
"xByHash": false,
"ByHash": true,
"xPopulatePropertyId": false,
"PopulatePropertyId": true,
"xRootDirectory": "C:/Tmp/phares/Pictures",
"xxRootDirectory": "C:/Tmp/Phares/Compare/Images-1e85c0ba",
"xxxRootDirectory": "F:/Tmp/Phares/Compare/Not-Copy-Copy-1e85c0ba",
"xxxxRootDirectory": "C:/Tmp/Phares/Compare/Not-Copy-Copy-1e85c0ba",
"xxxxxRootDirectory": "F:/Tmp/Phares/2022-11-03-DCIM/DCIM/100D3400 2022",
"RootDirectory": "D:/1) Images A/Images-1e85c0ba/_"
}
} }
} }

View File

@ -38,7 +38,7 @@
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="7.0.5" /> <PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="7.0.5" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="7.0.5" /> <PackageReference Include="Microsoft.Extensions.Identity.Core" Version="7.0.5" />
<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" /> <PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />

View File

@ -20,7 +20,8 @@ public class Program
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
.AddEnvironmentVariables() .AddEnvironmentVariables()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true); .AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true)
.AddUserSecrets<Program>();
IConfigurationRoot configurationRoot = configurationBuilder.Build(); IConfigurationRoot configurationRoot = configurationBuilder.Build();
AppSettings appSettings = Models.Binder.AppSettings.Get(configurationRoot); AppSettings appSettings = Models.Binder.AppSettings.Get(configurationRoot);
if (appSettings.MaxDegreeOfParallelism > Environment.ProcessorCount) if (appSettings.MaxDegreeOfParallelism > Environment.ProcessorCount)

View File

@ -38,7 +38,7 @@
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="7.0.5" /> <PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="7.0.5" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="7.0.5" /> <PackageReference Include="Microsoft.Extensions.Identity.Core" Version="7.0.5" />
<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" /> <PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />

View File

@ -20,7 +20,8 @@ public class Program
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
.AddEnvironmentVariables() .AddEnvironmentVariables()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true); .AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true)
.AddUserSecrets<Program>();
IConfigurationRoot configurationRoot = configurationBuilder.Build(); IConfigurationRoot configurationRoot = configurationBuilder.Build();
AppSettings appSettings = Models.Binder.AppSettings.Get(configurationRoot); AppSettings appSettings = Models.Binder.AppSettings.Get(configurationRoot);
if (appSettings.MaxDegreeOfParallelism > Environment.ProcessorCount) if (appSettings.MaxDegreeOfParallelism > Environment.ProcessorCount)

View File

@ -35,7 +35,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.14.1" /> <PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="MetadataExtractor" Version="2.7.2" /> <PackageReference Include="MetadataExtractor" Version="2.8.0" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="ShellProgressBar" Version="5.2.0" /> <PackageReference Include="ShellProgressBar" Version="5.2.0" />
<PackageReference Include="System.Text.Json" Version="7.0.2" /> <PackageReference Include="System.Text.Json" Version="7.0.2" />

View File

@ -30,7 +30,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" /> <PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />

View File

@ -40,7 +40,8 @@ public partial class DragDropExplorer : Form
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
.AddEnvironmentVariables() .AddEnvironmentVariables()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true); .AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true)
.AddUserSecrets<Program>();
configurationRoot = configurationBuilder.Build(); configurationRoot = configurationBuilder.Build();
appSettings = Models.Binder.AppSettings.Get(configurationRoot); appSettings = Models.Binder.AppSettings.Get(configurationRoot);
if (string.IsNullOrEmpty(appSettings.WorkingDirectoryName)) if (string.IsNullOrEmpty(appSettings.WorkingDirectoryName))

View File

@ -1,6 +1,6 @@
namespace View_by_Distance.Drag_Drop_Explorer; namespace View_by_Distance.Drag_Drop_Explorer;
static class Program public class Program
{ {
/// <summary> /// <summary>
/// The main entry point for the application. /// The main entry point for the application.

View File

@ -30,7 +30,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" /> <PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />

View File

@ -39,7 +39,8 @@ public partial class DragDropMove : Form
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
.AddEnvironmentVariables() .AddEnvironmentVariables()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true); .AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true)
.AddUserSecrets<Program>();
configurationRoot = configurationBuilder.Build(); configurationRoot = configurationBuilder.Build();
appSettings = Models.Binder.AppSettings.Get(configurationRoot); appSettings = Models.Binder.AppSettings.Get(configurationRoot);
if (string.IsNullOrEmpty(appSettings.WorkingDirectoryName)) if (string.IsNullOrEmpty(appSettings.WorkingDirectoryName))
@ -201,10 +202,11 @@ public partial class DragDropMove : Form
List<(string, int, DateTime)> results = new(); List<(string, int, DateTime)> results = new();
DateTime dateTime; DateTime dateTime;
Shared.Models.Property property; Shared.Models.Property property;
Shared.Models.Methods.IBlurHasher? blurHasher = null;
string[] files = Directory.GetFiles(checkDirectory, "*", SearchOption.TopDirectoryOnly); string[] files = Directory.GetFiles(checkDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string file in files) foreach (string file in files)
{ {
property = Property.Models.A_Property.GetImageProperty(file); property = Property.Models.A_Property.GetImageProperty(blurHasher, file);
if (property.Id is null || property.DateTimeOriginal is null) if (property.Id is null || property.DateTimeOriginal is null)
continue; continue;
dateTime = property.DateTimeOriginal.Value.AddTicks(ticks); dateTime = property.DateTimeOriginal.Value.AddTicks(ticks);
@ -238,6 +240,7 @@ public partial class DragDropMove : Form
ticks++; ticks++;
} }
Shared.Models.Methods.IBlurHasher? blurHasher = null;
List<(string, int, DateTime)> collection = GetCollection(checkDirectory, minimumDateTime, maximumDateTime, ticks); List<(string, int, DateTime)> collection = GetCollection(checkDirectory, minimumDateTime, maximumDateTime, ticks);
ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, Array.Empty<Type>(), null) ?? throw new Exception(); ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, Array.Empty<Type>(), null) ?? throw new Exception();
foreach ((string file, int id, DateTime dateTime) in collection) foreach ((string file, int id, DateTime dateTime) in collection)
@ -252,7 +255,7 @@ public partial class DragDropMove : Form
bitmap.SetPropertyItem(propertyItem); bitmap.SetPropertyItem(propertyItem);
bitmap.Save(checkFile); bitmap.Save(checkFile);
bitmap.Dispose(); bitmap.Dispose();
property = Property.Models.A_Property.GetImageProperty(checkFile); property = Property.Models.A_Property.GetImageProperty(blurHasher, checkFile);
if (property.Id is null || property.Id.Value != id) if (property.Id is null || property.Id.Value != id)
throw new Exception(); throw new Exception();
} }
@ -287,10 +290,11 @@ public partial class DragDropMove : Form
_Logger.Error("bad file(s) or target file(s) or maximum directory doesn't equal 1!"); _Logger.Error("bad file(s) or target file(s) or maximum directory doesn't equal 1!");
else else
{ {
Shared.Models.Methods.IBlurHasher? blurHasher = null;
DateTime minimumDateTime = DateTime.ParseExact(Path.GetFileName(minimumDirectory.First()), format, null, System.Globalization.DateTimeStyles.None); DateTime minimumDateTime = DateTime.ParseExact(Path.GetFileName(minimumDirectory.First()), format, null, System.Globalization.DateTimeStyles.None);
DateTime maximumDateTime = DateTime.ParseExact(Path.GetFileName(maximumDirectory.First()), format, null, System.Globalization.DateTimeStyles.None).AddHours(23); DateTime maximumDateTime = DateTime.ParseExact(Path.GetFileName(maximumDirectory.First()), format, null, System.Globalization.DateTimeStyles.None).AddHours(23);
Shared.Models.Property badProperty = Property.Models.A_Property.GetImageProperty(badFiles.First()); Shared.Models.Property badProperty = Property.Models.A_Property.GetImageProperty(blurHasher, badFiles.First());
Shared.Models.Property targetProperty = Property.Models.A_Property.GetImageProperty(targetFiles.First()); Shared.Models.Property targetProperty = Property.Models.A_Property.GetImageProperty(blurHasher, targetFiles.First());
if (badProperty.DateTimeOriginal is null || targetProperty.DateTimeOriginal is null) if (badProperty.DateTimeOriginal is null || targetProperty.DateTimeOriginal is null)
_Logger.Error("Date is null!"); _Logger.Error("Date is null!");
else else

View File

@ -1,6 +1,6 @@
namespace View_by_Distance.Drag_Drop_Explorer; namespace View_by_Distance.Drag_Drop_Explorer;
static class Program public class Program
{ {
/// <summary> /// <summary>
/// The main entry point for the application. /// The main entry point for the application.

View File

@ -30,7 +30,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" /> <PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />

View File

@ -44,7 +44,8 @@ public partial class DragDropSearch : Form
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
.AddEnvironmentVariables() .AddEnvironmentVariables()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true); .AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true)
.AddUserSecrets<Program>();
configurationRoot = configurationBuilder.Build(); configurationRoot = configurationBuilder.Build();
appSettings = Models.Binder.AppSettings.Get(configurationRoot); appSettings = Models.Binder.AppSettings.Get(configurationRoot);
if (string.IsNullOrEmpty(appSettings.WorkingDirectoryName)) if (string.IsNullOrEmpty(appSettings.WorkingDirectoryName))

View File

@ -2,7 +2,7 @@ using View_by_Distance.Shared.Models;
namespace View_by_Distance.Drag_Drop; namespace View_by_Distance.Drag_Drop;
static class Program public class Program
{ {
/// <summary> /// <summary>
/// The main entry point for the application. /// The main entry point for the application.

View File

@ -38,7 +38,7 @@
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="7.0.5" /> <PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="7.0.5" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="7.0.5" /> <PackageReference Include="Microsoft.Extensions.Identity.Core" Version="7.0.5" />
<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" /> <PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />

View File

@ -20,7 +20,8 @@ public class Program
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
.AddEnvironmentVariables() .AddEnvironmentVariables()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true); .AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true)
.AddUserSecrets<Program>();
IConfigurationRoot configurationRoot = configurationBuilder.Build(); IConfigurationRoot configurationRoot = configurationBuilder.Build();
AppSettings appSettings = Models.Binder.AppSettings.Get(configurationRoot); AppSettings appSettings = Models.Binder.AppSettings.Get(configurationRoot);
if (appSettings.MaxDegreeOfParallelism > Environment.ProcessorCount) if (appSettings.MaxDegreeOfParallelism > Environment.ProcessorCount)

View File

@ -2,7 +2,9 @@
using Phares.Shared; using Phares.Shared;
using ShellProgressBar; using ShellProgressBar;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.Text.Json;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using View_by_Distance.Distance.Models; using View_by_Distance.Distance.Models;
using View_by_Distance.Face.Models; using View_by_Distance.Face.Models;
@ -30,6 +32,7 @@ public partial class DlibDotNet
private readonly Serilog.ILogger? _Log; private readonly Serilog.ILogger? _Log;
private readonly D2_FaceParts _FaceParts; private readonly D2_FaceParts _FaceParts;
private readonly AppSettings _AppSettings; private readonly AppSettings _AppSettings;
private readonly IBlurHasher _IBlurHasher;
private readonly List<string> _Exceptions; private readonly List<string> _Exceptions;
private readonly IsEnvironment _IsEnvironment; private readonly IsEnvironment _IsEnvironment;
private readonly bool _PropertyRootExistedBefore; private readonly bool _PropertyRootExistedBefore;
@ -56,6 +59,7 @@ public partial class DlibDotNet
long ticks = DateTime.Now.Ticks; long ticks = DateTime.Now.Ticks;
_Exceptions = new List<string>(); _Exceptions = new List<string>();
_Log = Serilog.Log.ForContext<DlibDotNet>(); _Log = Serilog.Log.ForContext<DlibDotNet>();
_IBlurHasher = new BlurHash.Models.BlurHasher();
Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot); Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot);
Models.Configuration configuration = Models.Binder.Configuration.Get(isEnvironment, configurationRoot, propertyConfiguration); Models.Configuration configuration = Models.Binder.Configuration.Get(isEnvironment, configurationRoot, propertyConfiguration);
_Log.Information(propertyConfiguration.RootDirectory); _Log.Information(propertyConfiguration.RootDirectory);
@ -367,12 +371,37 @@ public partial class DlibDotNet
if (_Log is null) if (_Log is null)
throw new NullReferenceException(nameof(_Log)); throw new NullReferenceException(nameof(_Log));
List<Shared.Models.Face> faces; List<Shared.Models.Face> faces;
Shared.Models.Property property;
long ticks = DateTime.Now.Ticks; long ticks = DateTime.Now.Ticks;
DateTime dateTime = DateTime.Now; DateTime dateTime = DateTime.Now;
Shared.Models.Property? property;
List<string> parseExceptions = new(); List<string> parseExceptions = new();
List<Tuple<string, DateTime>> subFileTuples = new(); List<Tuple<string, DateTime>> subFileTuples = new();
List<KeyValuePair<string, string>> metadataCollection; List<KeyValuePair<string, string>> metadataCollection;
if (item.Property is not null && item.Property.Id is not null && !item.Any() && item.Property.BlurHash is null)
{
(string aResultsFullGroupDirectory, _) = GetResultsFullGroupDirectories();
string aPropertySingletonDirectory = Path.Combine(aResultsFullGroupDirectory, "{}");
string[] files = Directory.GetFiles(aPropertySingletonDirectory, $"{item.Property.Id.Value}*", SearchOption.AllDirectories);
if (files.Length == 1)
{
string matchFile = files.First();
string json = File.ReadAllText(matchFile);
string find = "\"CreationTime\":";
if (!json.Contains(find))
throw new NotImplementedException();
#pragma warning disable CA1416
using Image image = Image.FromFile(item.ImageFileHolder.FullName);
#pragma warning restore CA1416
string blurHash = _IBlurHasher.Encode(image);
json = json.Replace(find, $"\"{nameof(item.Property.BlurHash)}\": \"{blurHash}\", {find}");
property = JsonSerializer.Deserialize<Shared.Models.Property>(json);
if (property is null || property.BlurHash is null)
throw new NullReferenceException(nameof(property));
json = JsonSerializer.Serialize(property, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(matchFile, json);
File.SetLastWriteTime(matchFile, item.Property.LastWriteTime);
}
}
if (item.Property is not null && item.Property.Id is not null && !item.Any()) if (item.Property is not null && item.Property.Id is not null && !item.Any())
{ {
property = item.Property; property = item.Property;
@ -398,7 +427,7 @@ public partial class DlibDotNet
_Log.Information(string.Concat("LastWriteTimeChanged <", item.ImageFileHolder.FullName, '>')); _Log.Information(string.Concat("LastWriteTimeChanged <", item.ImageFileHolder.FullName, '>'));
else if (item.Moved.HasValue && item.Moved.Value) else if (item.Moved.HasValue && item.Moved.Value)
_Log.Information(string.Concat("Moved <", item.ImageFileHolder.FullName, '>')); _Log.Information(string.Concat("Moved <", item.ImageFileHolder.FullName, '>'));
property = propertyLogic.GetProperty(item, subFileTuples, parseExceptions); property = propertyLogic.GetProperty(_IBlurHasher, item, subFileTuples, parseExceptions);
item.Update(property); item.Update(property);
if (propertyHashCode is null) if (propertyHashCode is null)
{ {
@ -1134,7 +1163,7 @@ public partial class DlibDotNet
List<Shared.Models.Face> distinctFilteredFaces = Map.Models.Stateless.Methods.IMapLogic.GetFaces(distinctFilteredItems); List<Shared.Models.Face> distinctFilteredFaces = Map.Models.Stateless.Methods.IMapLogic.GetFaces(distinctFilteredItems);
Mapping[] distinctFilteredMappingCollection = GetMappings(_Configuration.PropertyConfiguration, containers, mapLogic, distinctItems: true); Mapping[] distinctFilteredMappingCollection = GetMappings(_Configuration.PropertyConfiguration, containers, mapLogic, distinctItems: true);
int totalNotMapped = mapLogic.UpdateMappingFromPerson(distinctFilteredMappingCollection); int totalNotMapped = mapLogic.UpdateMappingFromPerson(distinctFilteredMappingCollection);
string json = System.Text.Json.JsonSerializer.Serialize(distinctFilteredMappingCollection); string json = JsonSerializer.Serialize(distinctFilteredMappingCollection);
File.WriteAllText(Path.Combine(eDistanceContentDirectory, $"{ticks}.json"), json); File.WriteAllText(Path.Combine(eDistanceContentDirectory, $"{ticks}.json"), json);
for (int i = 1; i < 5; i++) for (int i = 1; i < 5; i++)
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(eDistanceContentDirectory); _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(eDistanceContentDirectory);

View File

@ -40,8 +40,8 @@
<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" />
<PackageReference Include="System.Drawing.Common" Version="7.0.0" /> <PackageReference Include="System.Drawing.Common" Version="7.0.0" />
<PackageReference Include="System.Text.Json" Version="7.0.2" /> <PackageReference Include="System.Text.Json" Version="7.0.2" />
<PackageReference Include="MetadataExtractor" Version="2.7.2" /> <PackageReference Include="MetadataExtractor" Version="2.8.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" /> <PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />
@ -49,6 +49,7 @@
<PackageReference Include="WindowsShortcutFactory" Version="1.1.0" /> <PackageReference Include="WindowsShortcutFactory" Version="1.1.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\BlurHash\BlurHash.csproj" />
<ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" /> <ProjectReference Include="..\FaceRecognitionDotNet\FaceRecognitionDotNet.csproj" />
<ProjectReference Include="..\Distance\Distance.csproj" /> <ProjectReference Include="..\Distance\Distance.csproj" />
<ProjectReference Include="..\Face\Face.csproj" /> <ProjectReference Include="..\Face\Face.csproj" />

View File

@ -19,7 +19,8 @@ public class Program
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
.AddEnvironmentVariables() .AddEnvironmentVariables()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true); .AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true)
.AddUserSecrets<Program>();
IConfigurationRoot configurationRoot = configurationBuilder.Build(); IConfigurationRoot configurationRoot = configurationBuilder.Build();
AppSettings appSettings = Models.Binder.AppSettings.Get(configurationRoot); AppSettings appSettings = Models.Binder.AppSettings.Get(configurationRoot);
if (appSettings.MaxDegreeOfParallelism > Environment.ProcessorCount) if (appSettings.MaxDegreeOfParallelism > Environment.ProcessorCount)

View File

@ -35,7 +35,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.14.1" /> <PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="MetadataExtractor" Version="2.7.2" /> <PackageReference Include="MetadataExtractor" Version="2.8.0" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="ShellProgressBar" Version="5.2.0" /> <PackageReference Include="ShellProgressBar" Version="5.2.0" />
<PackageReference Include="WindowsShortcutFactory" Version="1.1.0" /> <PackageReference Include="WindowsShortcutFactory" Version="1.1.0" />

View File

@ -34,7 +34,7 @@
<SupportedPlatform Include="browser" /> <SupportedPlatform Include="browser" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MetadataExtractor" Version="2.7.2" /> <PackageReference Include="MetadataExtractor" Version="2.8.0" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="System.Text.Json" Version="7.0.2" /> <PackageReference Include="System.Text.Json" Version="7.0.2" />
</ItemGroup> </ItemGroup>

View File

@ -38,7 +38,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" /> <PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />

View File

@ -20,7 +20,8 @@ public class Program
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
.AddEnvironmentVariables() .AddEnvironmentVariables()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true); .AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true)
.AddUserSecrets<Program>();
IConfigurationRoot configurationRoot = configurationBuilder.Build(); IConfigurationRoot configurationRoot = configurationBuilder.Build();
AppSettings appSettings = Models.Binder.AppSettings.Get(configurationRoot); AppSettings appSettings = Models.Binder.AppSettings.Get(configurationRoot);
if (appSettings.MaxDegreeOfParallelism > Environment.ProcessorCount) if (appSettings.MaxDegreeOfParallelism > Environment.ProcessorCount)

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<LangVersion>10.0</LangVersion> <LangVersion>10.0</LangVersion>
@ -39,7 +39,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" /> <PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />

View File

@ -20,7 +20,8 @@ public class Program
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
.AddEnvironmentVariables() .AddEnvironmentVariables()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true); .AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true)
.AddUserSecrets<Program>();
IConfigurationRoot configurationRoot = configurationBuilder.Build(); IConfigurationRoot configurationRoot = configurationBuilder.Build();
AppSettings appSettings = Models.Binder.AppSettings.Get(configurationRoot); AppSettings appSettings = Models.Binder.AppSettings.Get(configurationRoot);
if (appSettings.MaxDegreeOfParallelism > Environment.ProcessorCount) if (appSettings.MaxDegreeOfParallelism > Environment.ProcessorCount)

View File

@ -35,7 +35,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.14.1" /> <PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="MetadataExtractor" Version="2.7.2" /> <PackageReference Include="MetadataExtractor" Version="2.8.0" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="ShellProgressBar" Version="5.2.0" /> <PackageReference Include="ShellProgressBar" Version="5.2.0" />
<PackageReference Include="WindowsShortcutFactory" Version="1.1.0" /> <PackageReference Include="WindowsShortcutFactory" Version="1.1.0" />

View File

@ -37,12 +37,12 @@
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="ShellProgressBar" Version="5.2.0" /> <PackageReference Include="ShellProgressBar" Version="5.2.0" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" /> <PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="System.Drawing.Common" Version="7.0.0" /> <PackageReference Include="System.Drawing.Common" Version="7.0.0" />
<PackageReference Include="System.Text.Json" Version="7.0.2" /> <PackageReference Include="System.Text.Json" Version="7.0.2" />
<PackageReference Include="MetadataExtractor" Version="2.7.2" /> <PackageReference Include="MetadataExtractor" Version="2.8.0" />
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="7.0.5" /> <PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="7.0.5" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="7.0.5" /> <PackageReference Include="Microsoft.Extensions.Identity.Core" Version="7.0.5" />
<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" />

View File

@ -20,7 +20,8 @@ public class Program
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
.AddEnvironmentVariables() .AddEnvironmentVariables()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true); .AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true)
.AddUserSecrets<Program>();
IConfigurationRoot configurationRoot = configurationBuilder.Build(); IConfigurationRoot configurationRoot = configurationBuilder.Build();
AppSettings appSettings = Models.Binder.AppSettings.Get(configurationRoot); AppSettings appSettings = Models.Binder.AppSettings.Get(configurationRoot);
if (appSettings.MaxDegreeOfParallelism > Environment.ProcessorCount) if (appSettings.MaxDegreeOfParallelism > Environment.ProcessorCount)

View File

@ -102,7 +102,7 @@ public class A_Property
return results; return results;
} }
private static Shared.Models.Property GetImageProperty(FileHolder fileHolder, Shared.Models.Property? property, bool populateId, bool isIgnoreExtension, bool isValidImageFormatExtension, bool isValidMetadataExtensions, int? id, ASCIIEncoding asciiEncoding, bool writeBitmapDataBytes, string? angleBracket) private static Shared.Models.Property GetImageProperty(Shared.Models.Methods.IBlurHasher? blurHasher, FileHolder fileHolder, Shared.Models.Property? property, bool populateId, bool isIgnoreExtension, bool isValidImageFormatExtension, bool isValidMetadataExtensions, int? id, ASCIIEncoding asciiEncoding, bool writeBitmapDataBytes, string? angleBracket)
{ {
Shared.Models.Property result; Shared.Models.Property result;
byte[] bytes; byte[] bytes;
@ -114,6 +114,7 @@ public class A_Property
string? model = null; string? model = null;
string dateTimeFormat; string dateTimeFormat;
DateTime checkDateTime; DateTime checkDateTime;
string? blurHash = null;
DateTime? dateTime = null; DateTime? dateTime = null;
PropertyItem? propertyItem; PropertyItem? propertyItem;
string? orientation = null; string? orientation = null;
@ -150,6 +151,16 @@ public class A_Property
File.WriteAllBytes(Path.ChangeExtension(contentFileInfo.FullName, string.Empty), bytes); File.WriteAllBytes(Path.ChangeExtension(contentFileInfo.FullName, string.Empty), bytes);
} }
} }
if (blurHasher is not null && property?.BlurHash is null)
{
if (angleBracket is null)
blurHash = blurHasher.Encode(image);
else
{
string blurHashDirectory = angleBracket.Replace("<>", "()");
blurHash = blurHasher.EncodeAndSave(image, blurHashDirectory);
}
}
width = image.Width; width = image.Width;
height = image.Height; height = image.Height;
dateTimeFormat = Shared.Models.Stateless.Methods.IProperty.DateTimeFormat(); dateTimeFormat = Shared.Models.Stateless.Methods.IProperty.DateTimeFormat();
@ -242,15 +253,15 @@ public class A_Property
if (fileHolder.LastWriteTime is null && property?.LastWriteTime is null) if (fileHolder.LastWriteTime is null && property?.LastWriteTime is null)
throw new NullReferenceException(nameof(fileHolder.LastWriteTime)); throw new NullReferenceException(nameof(fileHolder.LastWriteTime));
if (fileHolder.CreationTime is not null && fileHolder.LastWriteTime is not null) if (fileHolder.CreationTime is not null && fileHolder.LastWriteTime is not null)
result = new(fileHolder.CreationTime.Value, dateTime, dateTimeDigitized, dateTimeFromName, dateTimeOriginal, fileLength, gpsDateStamp, height, id, fileHolder.LastWriteTime.Value, make, model, orientation, width); result = new(blurHash, fileHolder.CreationTime.Value, dateTime, dateTimeDigitized, dateTimeFromName, dateTimeOriginal, fileLength, gpsDateStamp, height, id, fileHolder.LastWriteTime.Value, make, model, orientation, width);
else if (property is not null) else if (property is not null)
result = new(property.CreationTime, dateTime, dateTimeDigitized, dateTimeFromName, dateTimeOriginal, fileLength, gpsDateStamp, height, id, property.LastWriteTime, make, model, orientation, width); result = new(blurHash, property.CreationTime, dateTime, dateTimeDigitized, dateTimeFromName, dateTimeOriginal, fileLength, gpsDateStamp, height, id, property.LastWriteTime, make, model, orientation, width);
else else
throw new NullReferenceException(nameof(property)); throw new NullReferenceException(nameof(property));
return result; return result;
} }
public static Shared.Models.Property GetImageProperty(string fileName) public static Shared.Models.Property GetImageProperty(Shared.Models.Methods.IBlurHasher? blurHasher, string fileName)
{ {
int? id = null; int? id = null;
bool populateId = true; bool populateId = true;
@ -262,18 +273,18 @@ public class A_Property
FileHolder fileHolder = new(fileName); FileHolder fileHolder = new(fileName);
bool isValidImageFormatExtension = true; bool isValidImageFormatExtension = true;
Shared.Models.Property? property = null; Shared.Models.Property? property = null;
Shared.Models.Property result = GetImageProperty(fileHolder, property, populateId, isIgnoreExtension, isValidImageFormatExtension, isValidMetadataExtensions, id, asciiEncoding, writeBitmapDataBytes, angleBracket); Shared.Models.Property result = GetImageProperty(blurHasher, fileHolder, property, populateId, isIgnoreExtension, isValidImageFormatExtension, isValidMetadataExtensions, id, asciiEncoding, writeBitmapDataBytes, angleBracket);
return result; return result;
} }
#pragma warning restore CA1416 #pragma warning restore CA1416
private Shared.Models.Property GetPropertyOfPrivate(Item item, List<Tuple<string, DateTime>> sourceDirectoryFileTuples, List<string> parseExceptions, bool isIgnoreExtension, bool isValidMetadataExtensions) private Shared.Models.Property GetPropertyOfPrivate(Shared.Models.Methods.IBlurHasher? blurHasher, Item item, List<Tuple<string, DateTime>> sourceDirectoryFileTuples, List<string> parseExceptions, bool isIgnoreExtension, bool isValidMetadataExtensions)
{ {
Shared.Models.Property? result; Shared.Models.Property? result;
string json;
int? id = null; int? id = null;
FileInfo fileInfo; FileInfo fileInfo;
string? json = null;
bool hasWrongYearProperty = false; bool hasWrongYearProperty = false;
string[] changesFrom = Array.Empty<string>(); string[] changesFrom = Array.Empty<string>();
string angleBracket = _AngleBracketCollection[0]; string angleBracket = _AngleBracketCollection[0];
@ -356,10 +367,28 @@ public class A_Property
parseExceptions.Add(nameof(A_Property)); parseExceptions.Add(nameof(A_Property));
} }
} }
if (!string.IsNullOrEmpty(json) && result is not null && blurHasher is not null && result.BlurHash is null)
{
string find = "\"CreationTime\":";
if (!json.Contains(find))
throw new NotImplementedException();
string blurHashDirectory = angleBracket.Replace("<>", "()");
#pragma warning disable CA1416
using Image image = Image.FromFile(item.ImageFileHolder.FullName);
#pragma warning restore CA1416
string blurHash = blurHasher.EncodeAndSave(image, blurHashDirectory);
json = json.Replace(find, $"\"{nameof(result.BlurHash)}\": \"{blurHash}\", {find}");
result = JsonSerializer.Deserialize<Shared.Models.Property>(json);
if (result is null || result.BlurHash is null)
throw new NullReferenceException(nameof(result));
json = JsonSerializer.Serialize(result, _WriteIndentedJsonSerializerOptions);
File.WriteAllText(fileInfo.FullName, json);
File.SetLastWriteTime(fileInfo.FullName, fileInfo.LastWriteTime);
}
if (result is null) if (result is null)
{ {
id ??= item.ImageFileHolder.Id; id ??= item.ImageFileHolder.Id;
result = GetImageProperty(item.ImageFileHolder, result, populateId, isIgnoreExtension, item.IsValidImageFormatExtension, isValidMetadataExtensions, id, _ASCIIEncoding, _Configuration.WriteBitmapDataBytes, angleBracket); result = GetImageProperty(blurHasher, item.ImageFileHolder, result, populateId, isIgnoreExtension, item.IsValidImageFormatExtension, isValidMetadataExtensions, id, _ASCIIEncoding, _Configuration.WriteBitmapDataBytes, angleBracket);
json = JsonSerializer.Serialize(result, _WriteIndentedJsonSerializerOptions); json = JsonSerializer.Serialize(result, _WriteIndentedJsonSerializerOptions);
if (populateId && Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true)) if (populateId && Shared.Models.Stateless.Methods.IPath.WriteAllText(fileInfo.FullName, json, updateDateWhenMatches: true, compareBeforeWrite: true))
{ {
@ -388,7 +417,7 @@ public class A_Property
return result; return result;
} }
private void SavePropertyParallelForWork(string sourceDirectory, List<Tuple<string, DateTime>> sourceDirectoryFileTuples, List<Tuple<string, DateTime>> sourceDirectoryChanges, Item item) private void SavePropertyParallelForWork(Shared.Models.Methods.IBlurHasher? blurHasher, string sourceDirectory, List<Tuple<string, DateTime>> sourceDirectoryFileTuples, List<Tuple<string, DateTime>> sourceDirectoryChanges, Item item)
{ {
Shared.Models.Property property; Shared.Models.Property property;
List<string> parseExceptions = new(); List<string> parseExceptions = new();
@ -399,7 +428,7 @@ public class A_Property
File.Move(item.ImageFileHolder.FullName, filteredSourceDirectoryFileExtensionLowered); File.Move(item.ImageFileHolder.FullName, filteredSourceDirectoryFileExtensionLowered);
if (item.FileSizeChanged is null || item.FileSizeChanged.Value || item.LastWriteTimeChanged is null || item.LastWriteTimeChanged.Value || item.Property is null) if (item.FileSizeChanged is null || item.FileSizeChanged.Value || item.LastWriteTimeChanged is null || item.LastWriteTimeChanged.Value || item.Property is null)
{ {
property = GetPropertyOfPrivate(item, sourceDirectoryFileTuples, parseExceptions, isIgnoreExtension, isValidMetadataExtensions); property = GetPropertyOfPrivate(blurHasher, item, sourceDirectoryFileTuples, parseExceptions, isIgnoreExtension, isValidMetadataExtensions);
lock (sourceDirectoryChanges) lock (sourceDirectoryChanges)
sourceDirectoryChanges.Add(new Tuple<string, DateTime>(nameof(A_Property), DateTime.Now)); sourceDirectoryChanges.Add(new Tuple<string, DateTime>(nameof(A_Property), DateTime.Now));
lock (item) lock (item)
@ -407,10 +436,10 @@ public class A_Property
} }
} }
private void SavePropertyParallelWork(List<Exception> exceptions, List<Tuple<string, DateTime>> sourceDirectoryChanges, Container container, List<Item> items, string message) private void SavePropertyParallelWork(int maxDegreeOfParallelism, Shared.Models.Methods.IBlurHasher? blurHasher, List<Exception> exceptions, List<Tuple<string, DateTime>> sourceDirectoryChanges, Container container, List<Item> items, string message)
{ {
List<Tuple<string, DateTime>> sourceDirectoryFileTuples = new(); List<Tuple<string, DateTime>> sourceDirectoryFileTuples = new();
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = _MaxDegreeOfParallelism }; ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
using ProgressBar progressBar = new(items.Count, message, options); using ProgressBar progressBar = new(items.Count, message, options);
_ = Parallel.For(0, items.Count, parallelOptions, (i, state) => _ = Parallel.For(0, items.Count, parallelOptions, (i, state) =>
@ -420,7 +449,7 @@ public class A_Property
long ticks = DateTime.Now.Ticks; long ticks = DateTime.Now.Ticks;
DateTime dateTime = DateTime.Now; DateTime dateTime = DateTime.Now;
List<Tuple<string, DateTime>> collection; List<Tuple<string, DateTime>> collection;
SavePropertyParallelForWork(container.SourceDirectory, sourceDirectoryChanges, sourceDirectoryFileTuples, items[i]); SavePropertyParallelForWork(blurHasher, container.SourceDirectory, sourceDirectoryChanges, sourceDirectoryFileTuples, items[i]);
if (i == 0 || sourceDirectoryChanges.Any()) if (i == 0 || sourceDirectoryChanges.Any())
progressBar.Tick(); progressBar.Tick();
lock (sourceDirectoryFileTuples) lock (sourceDirectoryFileTuples)
@ -449,6 +478,9 @@ public class A_Property
singletonDescription: "Properties for each image", singletonDescription: "Properties for each image",
collectionDescription: string.Empty, collectionDescription: string.Empty,
converted: false)); converted: false));
string directory = _AngleBracketCollection[0].Replace("<>", "()");
if (!Directory.Exists(directory))
_ = Directory.CreateDirectory(directory);
} }
private void SetAngleBracketCollection(string sourceDirectory, bool anyNullOrNoIsUniqueFileName) private void SetAngleBracketCollection(string sourceDirectory, bool anyNullOrNoIsUniqueFileName)
@ -463,7 +495,7 @@ public class A_Property
SetAngleBracketCollection(aResultsFullGroupDirectory, sourceDirectory, anyNullOrNoIsUniqueFileName); SetAngleBracketCollection(aResultsFullGroupDirectory, sourceDirectory, anyNullOrNoIsUniqueFileName);
} }
public void SavePropertyParallelWork(long ticks, int t, Container[] containers) public void SavePropertyParallelWork(long ticks, int t, Container[] containers, Shared.Models.Methods.IBlurHasher? blurHasher)
{ {
if (_Log is null) if (_Log is null)
throw new NullReferenceException(nameof(_Log)); throw new NullReferenceException(nameof(_Log));
@ -489,7 +521,7 @@ public class A_Property
SetAngleBracketCollection(container.SourceDirectory, anyNullOrNoIsUniqueFileName); SetAngleBracketCollection(container.SourceDirectory, anyNullOrNoIsUniqueFileName);
totalSeconds = (int)Math.Truncate(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); 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}"; message = $"{i + 1:000} [{container.Items.Count:000}] / {containersLength:000} - {total} / {t} total - {totalSeconds} total second(s) - {outputResolution} - {container.SourceDirectory}";
SavePropertyParallelWork(exceptions, sourceDirectoryChanges, container, container.Items, message); SavePropertyParallelWork(_MaxDegreeOfParallelism, blurHasher, exceptions, sourceDirectoryChanges, container, container.Items, message);
foreach (Exception exception in exceptions) foreach (Exception exception in exceptions)
_Log.Error(string.Concat(container.SourceDirectory, Environment.NewLine, exception.Message, Environment.NewLine, exception.StackTrace), exception); _Log.Error(string.Concat(container.SourceDirectory, Environment.NewLine, exception.Message, Environment.NewLine, exception.StackTrace), exception);
if (exceptions.Count == container.Items.Count) if (exceptions.Count == container.Items.Count)
@ -510,7 +542,7 @@ public class A_Property
} }
} }
public Shared.Models.Property GetProperty(Item item, List<Tuple<string, DateTime>> sourceDirectoryFileTuples, List<string> parseExceptions) public Shared.Models.Property GetProperty(Shared.Models.Methods.IBlurHasher? blurHasher, Item item, List<Tuple<string, DateTime>> sourceDirectoryFileTuples, List<string> parseExceptions)
{ {
Shared.Models.Property result; Shared.Models.Property result;
bool angleBracketCollectionAny = _AngleBracketCollection.Any(); bool angleBracketCollectionAny = _AngleBracketCollection.Any();
@ -522,7 +554,7 @@ public class A_Property
} }
bool isValidMetadataExtensions = _Configuration.ValidMetadataExtensions.Contains(item.ImageFileHolder.ExtensionLowered); bool isValidMetadataExtensions = _Configuration.ValidMetadataExtensions.Contains(item.ImageFileHolder.ExtensionLowered);
bool isIgnoreExtension = item.IsValidImageFormatExtension && _Configuration.IgnoreExtensions.Contains(item.ImageFileHolder.ExtensionLowered); bool isIgnoreExtension = item.IsValidImageFormatExtension && _Configuration.IgnoreExtensions.Contains(item.ImageFileHolder.ExtensionLowered);
result = GetPropertyOfPrivate(item, sourceDirectoryFileTuples, parseExceptions, isIgnoreExtension, isValidMetadataExtensions); result = GetPropertyOfPrivate(blurHasher, item, sourceDirectoryFileTuples, parseExceptions, isIgnoreExtension, isValidMetadataExtensions);
if (!angleBracketCollectionAny) if (!angleBracketCollectionAny)
_AngleBracketCollection.Clear(); _AngleBracketCollection.Clear();
return result; return result;

View File

@ -40,10 +40,10 @@
<SupportedPlatform Include="browser" /> <SupportedPlatform Include="browser" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MetadataExtractor" Version="2.7.2" /> <PackageReference Include="MetadataExtractor" Version="2.8.0" />
<PackageReference Include="ShellProgressBar" Version="5.2.0" /> <PackageReference Include="ShellProgressBar" Version="5.2.0" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" /> <PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
<PackageReference Include="System.Drawing.Common" Version="7.0.0" /> <PackageReference Include="System.Drawing.Common" Version="7.0.0" />
<PackageReference Include="System.Text.Json" Version="7.0.2" /> <PackageReference Include="System.Text.Json" Version="7.0.2" />
</ItemGroup> </ItemGroup>

View File

@ -0,0 +1,9 @@
{
"_Application": "Rename",
"ComparePathsFile": "C:/Users/mikep/AppData/Local/PharesApps/Drag-Drop-Explorer/2023_21/638202586000194405.json",
"Windows": {
"Configuration": {
"RootDirectory": "D:/1) Images A/Images-1e85c0ba"
}
}
}

View File

@ -1,41 +1,76 @@
{ {
"version": "2.0.0", "version": "2.0.0",
"options": {
"env": {
"serverUserSecretsId": "6e026d2f-9edf-4c6c-a042-162758114e9a"
}
},
"tasks": [ "tasks": [
{
"label": "userSecretsInit",
"command": "dotnet",
"type": "process",
"args": [
"user-secrets",
"-p",
"${workspaceFolder}/Rename.csproj",
"init"
],
"problemMatcher": "$msCompile"
},
{
"label": "userSecretsSet",
"command": "dotnet",
"type": "process",
"args": [
"user-secrets",
"-p",
"${workspaceFolder}/Rename.csproj",
"set",
"SaveDirectory",
"D:/1) Images A/Images-1e85c0ba-Results/A2) People/1e85c0ba/([])"
],
"problemMatcher": "$msCompile"
},
{
"label": "userSecretsMkLink",
"command": "cmd",
"type": "shell",
"args": [
"/c",
"mklink",
"/J",
".vscode\\UserSecrets",
"${userHome}\\AppData\\Roaming\\Microsoft\\UserSecrets\\$env:serverUserSecretsId"
],
"problemMatcher": "$msCompile"
},
{
"label": "format",
"command": "dotnet",
"type": "process",
"args": [
"format",
"--report",
".vscode",
"--verbosity",
"detailed",
"--severity",
"warn"
],
"problemMatcher": "$msCompile"
},
{ {
"label": "build", "label": "build",
"command": "dotnet", "command": "dotnet",
"type": "process", "type": "process",
"args": [ "args": [
"build", "build",
"${workspaceFolder}/Rename.csproj", "${workspaceFolder}/View-by-Distance-MKLink-Console.sln",
"/property:GenerateFullPaths=true", "/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary" "/consoleloggerparameters:NoSummary"
], ],
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/Rename.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/Rename.csproj"
],
"problemMatcher": "$msCompile"
} }
] ]
} }

View File

@ -20,7 +20,8 @@ public class Program
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder() IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
.AddEnvironmentVariables() .AddEnvironmentVariables()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true); .AddJsonFile(isEnvironment.AppSettingsFileName, optional: false, reloadOnChange: true)
.AddUserSecrets<Program>();
IConfigurationRoot configurationRoot = configurationBuilder.Build(); IConfigurationRoot configurationRoot = configurationBuilder.Build();
AppSettings appSettings = Models.Binder.AppSettings.Get(configurationRoot); AppSettings appSettings = Models.Binder.AppSettings.Get(configurationRoot);
if (appSettings.MaxDegreeOfParallelism > Environment.ProcessorCount) if (appSettings.MaxDegreeOfParallelism > Environment.ProcessorCount)

View File

@ -3,9 +3,11 @@ using Phares.Shared;
using Serilog; using Serilog;
using ShellProgressBar; using ShellProgressBar;
using System.Text.Json; using System.Text.Json;
using View_by_Distance.Property.Models;
using View_by_Distance.Rename.Models; using View_by_Distance.Rename.Models;
using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models;
using View_by_Distance.Shared.Models.Methods; using View_by_Distance.Shared.Models.Methods;
using View_by_Distance.Shared.Models.Stateless.Methods;
namespace View_by_Distance.Rename; namespace View_by_Distance.Rename;
@ -15,7 +17,7 @@ public class Rename
private readonly AppSettings _AppSettings; private readonly AppSettings _AppSettings;
private readonly string _WorkingDirectory; private readonly string _WorkingDirectory;
private readonly IsEnvironment _IsEnvironment; private readonly IsEnvironment _IsEnvironment;
private readonly Configuration _Configuration; private readonly Models.Configuration _Configuration;
private readonly IConfigurationRoot _ConfigurationRoot; private readonly IConfigurationRoot _ConfigurationRoot;
private readonly Property.Models.Configuration _PropertyConfiguration; private readonly Property.Models.Configuration _PropertyConfiguration;
@ -34,7 +36,7 @@ public class Rename
ILogger? log = Log.ForContext<Rename>(); ILogger? log = Log.ForContext<Rename>();
Dictionary<long, Dictionary<long, List<string>>> fileSizeToCollection = new(); Dictionary<long, Dictionary<long, List<string>>> fileSizeToCollection = new();
Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot); Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot);
Configuration configuration = Models.Binder.Configuration.Get(isEnvironment, configurationRoot, propertyConfiguration); Models.Configuration configuration = Models.Binder.Configuration.Get(isEnvironment, configurationRoot, propertyConfiguration);
_PropertyConfiguration = propertyConfiguration; _PropertyConfiguration = propertyConfiguration;
_Configuration = configuration; _Configuration = configuration;
propertyConfiguration.Update(); propertyConfiguration.Update();
@ -63,6 +65,8 @@ public class Rename
MoveMatches(matchNginxCollection[0]); MoveMatches(matchNginxCollection[0]);
else if (matchNginxCollection.All(l => l.Name.StartsWith("#")) || matchNginxCollection.All(l => l.Name.StartsWith(" #")) || matchNginxCollection.All(l => l.Name.StartsWith("=20")) || matchNginxCollection.All(l => l.Name.StartsWith("#20"))) else if (matchNginxCollection.All(l => l.Name.StartsWith("#")) || matchNginxCollection.All(l => l.Name.StartsWith(" #")) || matchNginxCollection.All(l => l.Name.StartsWith("=20")) || matchNginxCollection.All(l => l.Name.StartsWith("#20")))
Rename2000(log, matchNginxCollection); Rename2000(log, matchNginxCollection);
else if (matchNginxCollection.All(l => l.Name.Length > 4) && matchNginxCollection.All(l => l.Name[0..3] is "198" or "199" or "200" or "201"))
RenameByDateTaken(log, matchNginxCollection);
else if (matchNginxCollection.Any()) else if (matchNginxCollection.Any())
{ {
List<string> lines = RenameFilesInDirectories(log, matchNginxCollection); List<string> lines = RenameFilesInDirectories(log, matchNginxCollection);
@ -323,6 +327,8 @@ public class Rename
continue; continue;
if (File.Exists(matchNginx.ConvertedPath)) if (File.Exists(matchNginx.ConvertedPath))
continue; continue;
if (!Directory.Exists(matchNginx.ConvertedPath))
continue;
files = Directory.GetFiles(matchNginx.ConvertedPath, "*", SearchOption.AllDirectories); files = Directory.GetFiles(matchNginx.ConvertedPath, "*", SearchOption.AllDirectories);
if (files.All(l => l.EndsWith(".id"))) if (files.All(l => l.EndsWith(".id")))
{ {
@ -425,8 +431,8 @@ public class Rename
List<string> allFiles; List<string> allFiles;
ProgressBar progressBar; ProgressBar progressBar;
List<(FileHolder, string)> toDoCollection; List<(FileHolder, string)> toDoCollection;
List<(FileHolder, string)> verifiedToDoCollection;
allFiles = GetAllFiles(matchNginxCollection); allFiles = GetAllFiles(matchNginxCollection);
List<(FileHolder, string)> verifiedToDoCollection;
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
for (int i = 1; i < 3; i++) for (int i = 1; i < 3; i++)
{ {
@ -464,4 +470,88 @@ public class Rename
return results; return results;
} }
} private void RenameByDateTakenB(MatchNginx[] matchNginxCollection, string aPropertySingletonDirectory, string[] jsonFiles)
{
string json;
char directory;
string[] files;
string fileName;
string extension;
string[] matches;
string checkFile;
DateTime dateTime;
string[] segments;
string? checkFileName;
string checkDirectory;
string? subdirectory;
Shared.Models.Property? property;
foreach (MatchNginx matchNginx in matchNginxCollection)
{
if (File.Exists(matchNginx.ConvertedPath))
continue;
if (!Directory.Exists(matchNginx.ConvertedPath))
continue;
subdirectory = Path.GetDirectoryName(matchNginx.ConvertedPath);
if (string.IsNullOrEmpty(subdirectory))
continue;
files = Directory.GetFiles(matchNginx.ConvertedPath, "*", SearchOption.AllDirectories);
for (int i = 65; i < 91; i++)
{
checkDirectory = Path.Combine(subdirectory, nameof(Rename), ((char)i).ToString());
if (!Directory.Exists(checkDirectory))
_ = Directory.CreateDirectory(checkDirectory);
}
foreach (string file in files)
{
fileName = Path.GetFileName(file);
segments = fileName.Split('.');
extension = Path.GetExtension(file);
directory = IDirectory.GetDirectory(fileName);
checkFileName = $"{segments.First()}{Path.GetExtension(Path.GetFileNameWithoutExtension(file))}.json";
checkDirectory = Path.Combine(aPropertySingletonDirectory, _PropertyConfiguration.ResultAllInOne, directory.ToString());
checkFile = Path.Combine(checkDirectory, checkFileName);
matches = jsonFiles.Where(l => l == checkFile).ToArray();
if (!matches.Any())
{
matches = jsonFiles.Where(l => l.EndsWith(checkFileName)).ToArray();
if (!matches.Any())
continue;
}
json = File.ReadAllText(matches.First());
property = JsonSerializer.Deserialize<Shared.Models.Property>(json);
if (property is null)
continue;
checkFileName = null;
dateTime = property.DateTimeOriginal is not null ? property.DateTimeOriginal.Value : Shared.Models.Stateless.Methods.IProperty.GetMinimumDateTime(property);
for (int i = 65; i < 91; i++)
{
if (checkFileName is not null && !File.Exists(checkFileName))
break;
checkFileName = Path.Combine(subdirectory, nameof(Rename), ((char)i).ToString(), $"{dateTime.Ticks}{extension}");
}
if (checkFileName is null || File.Exists(checkFileName))
continue;
File.Move(file, checkFileName);
}
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(subdirectory);
}
}
private void RenameByDateTaken(ILogger log, MatchNginx[] matchNginxCollection)
{
string aResultsFullGroupDirectory = Property.Models.Stateless.IResult.GetResultsFullGroupDirectory(
_PropertyConfiguration,
nameof(A_Property),
string.Empty,
includeResizeGroup: false,
includeModel: false,
includePredictorModel: false);
string aPropertySingletonDirectory = Path.GetFullPath(Path.Combine(aResultsFullGroupDirectory, "{}"));
string[] jsonFiles = !Directory.Exists(aPropertySingletonDirectory) ? Array.Empty<string>() : Directory.GetFiles(aPropertySingletonDirectory, "*.json", SearchOption.AllDirectories);
if (!jsonFiles.Any())
log.Information($"No json file(s) found! Check directory <{aPropertySingletonDirectory}>");
else
RenameByDateTakenB(matchNginxCollection, aPropertySingletonDirectory, jsonFiles);
}
}

View File

@ -6,6 +6,7 @@
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<TargetFramework>net7.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<UserSecretsId>6e026d2f-9edf-4c6c-a042-162758114e9a</UserSecretsId>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<PackageId>Phares.View.by.Distance.Rename</PackageId> <PackageId>Phares.View.by.Distance.Rename</PackageId>
@ -38,7 +39,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" /> <PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />

View File

@ -1,14 +1,9 @@
{ {
"ComparePathsFile": "C:/Users/mikep/AppData/Local/PharesApps/Drag-Drop-Explorer/2023_13/638158781544395303.json",
"CopyTo": "",
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {
"Log4netProvider": "Debug" "Log4netProvider": "Debug"
} }
}, },
"MaxDegreeOfParallelism": 6,
"MaxMinutesDelta": 2,
"RenameUndo": false,
"Serilog": { "Serilog": {
"MinimumLevel": "Debug" "MinimumLevel": "Debug"
}, },

View File

@ -68,7 +68,7 @@
"ResultCollection": "[]", "ResultCollection": "[]",
"ResultContent": "()", "ResultContent": "()",
"ResultSingleton": "{}", "ResultSingleton": "{}",
"RootDirectory": "C:/Tmp/Phares/Compare/Images-1e85c0ba", "RootDirectory": "D:/Images",
"WriteBitmapDataBytes": false, "WriteBitmapDataBytes": false,
"IgnoreExtensions": [ "IgnoreExtensions": [
".gif", ".gif",

View File

@ -56,9 +56,7 @@ public class C_Resize
_PropertiesChangedForResize = propertiesChangedForResize; _PropertiesChangedForResize = propertiesChangedForResize;
_ForceResizeLastWriteTimeToCreationTime = forceResizeLastWriteTimeToCreationTime; _ForceResizeLastWriteTimeToCreationTime = forceResizeLastWriteTimeToCreationTime;
_WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; _WriteIndentedJsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true };
ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, Array.Empty<Type>(), null); ConstructorInfo? constructorInfo = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, Array.Empty<Type>(), null) ?? throw new Exception();
if (constructorInfo is null)
throw new Exception();
_ConstructorInfo = constructorInfo; _ConstructorInfo = constructorInfo;
} }

View File

@ -35,7 +35,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="MetadataExtractor" Version="2.7.2" /> <PackageReference Include="MetadataExtractor" Version="2.8.0" />
<PackageReference Include="System.Drawing.Common" Version="7.0.0" /> <PackageReference Include="System.Drawing.Common" Version="7.0.0" />
<PackageReference Include="System.Text.Json" Version="7.0.2" /> <PackageReference Include="System.Text.Json" Version="7.0.2" />
</ItemGroup> </ItemGroup>
@ -43,5 +43,6 @@
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" /> <ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
<ProjectReference Include="..\Metadata\Metadata.csproj" /> <ProjectReference Include="..\Metadata\Metadata.csproj" />
<ProjectReference Include="..\Property\Property.csproj" /> <ProjectReference Include="..\Property\Property.csproj" />
<ProjectReference Include="..\Property-Compare\Property-Compare.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,14 @@
using System.Drawing;
namespace View_by_Distance.Shared.Models.Methods;
public interface IBlurHasher
{
string Encode(Image image);
string Encode(Image image, int x, int y);
string EncodeAndSave(Image image, string directory);
string EncodeAndSave(Image image, int x, int y, string directory);
string EncodeAndSave(Image image, int x, int y, int width, int height, string directory);
}

View File

@ -3,6 +3,7 @@ namespace View_by_Distance.Shared.Models.Properties;
public interface IProperty public interface IProperty
{ {
public string? BlurHash { init; get; }
public DateTime CreationTime { init; get; } public DateTime CreationTime { init; get; }
public DateTime? DateTime { init; get; } public DateTime? DateTime { init; get; }
public DateTime? DateTimeDigitized { init; get; } public DateTime? DateTimeDigitized { init; get; }

View File

@ -6,6 +6,7 @@ namespace View_by_Distance.Shared.Models;
public class Property : Properties.IProperty public class Property : Properties.IProperty
{ {
public string? BlurHash { init; get; }
public DateTime CreationTime { init; get; } public DateTime CreationTime { init; get; }
public DateTime? DateTime { init; get; } public DateTime? DateTime { init; get; }
public DateTime? DateTimeDigitized { init; get; } public DateTime? DateTimeDigitized { init; get; }
@ -22,8 +23,9 @@ public class Property : Properties.IProperty
public int? Width { init; get; } public int? Width { init; get; }
[JsonConstructor] [JsonConstructor]
public Property(DateTime creationTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeFromName, DateTime? dateTimeOriginal, long fileSize, DateTime? gpsDateStamp, int? height, int? id, DateTime lastWriteTime, string? make, string? model, string? orientation, int? width) public Property(string? blurHash, DateTime creationTime, DateTime? dateTime, DateTime? dateTimeDigitized, DateTime? dateTimeFromName, DateTime? dateTimeOriginal, long fileSize, DateTime? gpsDateStamp, int? height, int? id, DateTime lastWriteTime, string? make, string? model, string? orientation, int? width)
{ {
BlurHash = blurHash;
DateTimeFromName = dateTimeFromName; DateTimeFromName = dateTimeFromName;
CreationTime = creationTime; CreationTime = creationTime;
DateTime = dateTime; DateTime = dateTime;

View File

@ -27,25 +27,25 @@
<DefineConstants>Linux</DefineConstants> <DefineConstants>Linux</DefineConstants>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="coverlet.collector" Version="3.2.0" /> <PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="Humanizer.Core" Version="2.14.1" /> <PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" /> <PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" /> <PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" /> <PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\BlurHash\BlurHash.csproj" />
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" /> <ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
<ProjectReference Include="..\Property\Property.csproj" /> <ProjectReference Include="..\Property\Property.csproj" />
<ProjectReference Include="..\Metadata\Metadata.csproj" /> <ProjectReference Include="..\Metadata\Metadata.csproj" />
<ProjectReference Include="..\Resize\Resize.csproj" /> <ProjectReference Include="..\Resize\Resize.csproj" />
<ProjectReference Include="..\Property-Compare\Property-Compare.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="..\Instance\appsettings.json"> <None Include="..\Instance\appsettings.json">

View File

@ -46,6 +46,13 @@ public class UnitTestIsEnvironment
_ConfigurationRoot = configurationRoot; _ConfigurationRoot = configurationRoot;
} }
private static void NonThrowTryCatch()
{
try
{ throw new Exception(); }
catch (Exception) { }
}
[TestMethod] [TestMethod]
public void TestMethodNull() public void TestMethodNull()
{ {

View File

@ -64,6 +64,13 @@ public class UnitTestResize
_PropertyConfiguration = propertyConfiguration; _PropertyConfiguration = propertyConfiguration;
} }
private static void NonThrowTryCatch()
{
try
{ throw new Exception(); }
catch (Exception) { }
}
[TestMethod] [TestMethod]
public void TestMethodNull() public void TestMethodNull()
{ {
@ -74,6 +81,7 @@ public class UnitTestResize
Assert.IsFalse(_WorkingDirectory is null); Assert.IsFalse(_WorkingDirectory is null);
Assert.IsFalse(_ConfigurationRoot is null); Assert.IsFalse(_ConfigurationRoot is null);
Assert.IsFalse(_PropertyConfiguration is null); Assert.IsFalse(_PropertyConfiguration is null);
NonThrowTryCatch();
} }
private A_Property GetPropertyLogic(bool reverse, string aResultsFullGroupDirectory) private A_Property GetPropertyLogic(bool reverse, string aResultsFullGroupDirectory)
@ -121,17 +129,8 @@ public class UnitTestResize
[TestMethod] [TestMethod]
public void TestMethodResize() public void TestMethodResize()
{ {
// string sourceFileName = "IMG_0067.jpg"; string sourceFileName = "640794601.jpg";
// string sourceDirectoryName = "Mackenzie Prom 2017"; // string sourceFileName = "input.jpg";
// string sourceFileName = "Fall 2005 (113).jpg";
// string sourceDirectoryName = "=2005.3 Fall";
// string sourceFileName = "DSCN0534.jpg";
// string sourceDirectoryName = "Logan Swimming Lessons 2013";
// string sourceFileName = "DSC_4913.jpg";
// string sourceDirectoryName = "Disneyland 2014";
// string sourceFileName = "Logan Michael Sept 08 (193).jpg";
// string sourceDirectoryName = "=2008.2 Summer Logan Michael";
string sourceFileName = "Halloween 2006 (112).jpg";
string sourceDirectoryName = "Halloween 2006"; string sourceDirectoryName = "Halloween 2006";
Item item; Item item;
bool reverse = false; bool reverse = false;
@ -145,7 +144,6 @@ public class UnitTestResize
int length = _PropertyConfiguration.RootDirectory.Length; int length = _PropertyConfiguration.RootDirectory.Length;
string outputResolution = _Configuration.OutputResolutions[0]; string outputResolution = _Configuration.OutputResolutions[0];
(string cResultsFullGroupDirectory, _, _) = GetResultsFullGroupDirectories(outputResolution); (string cResultsFullGroupDirectory, _, _) = GetResultsFullGroupDirectories(outputResolution);
string sourceDirectory = Path.Combine(_PropertyConfiguration.RootDirectory, sourceDirectoryName);
(string aResultsFullGroupDirectory, string bResultsFullGroupDirectory) = GetResultsFullGroupDirectories(); (string aResultsFullGroupDirectory, string bResultsFullGroupDirectory) = GetResultsFullGroupDirectories();
_Logger.Information(_Configuration.ModelDirectory); _Logger.Information(_Configuration.ModelDirectory);
A_Property propertyLogic = GetPropertyLogic(reverse, aResultsFullGroupDirectory); A_Property propertyLogic = GetPropertyLogic(reverse, aResultsFullGroupDirectory);
@ -160,16 +158,18 @@ public class UnitTestResize
bool isUniqueFileName = false; bool isUniqueFileName = false;
bool? isNotUniqueAndNeedsReview = null; bool? isNotUniqueAndNeedsReview = null;
FileHolder sourceDirectoryFileHolder = new(".json"); FileHolder sourceDirectoryFileHolder = new(".json");
string sourceDirectory = Path.GetFullPath(Path.Combine(_PropertyConfiguration.RootDirectory, sourceDirectoryName));
FileHolder fileHolder = new(Path.Combine(sourceDirectory, sourceFileName)); FileHolder fileHolder = new(Path.Combine(sourceDirectory, sourceFileName));
string relativePath = IPath.GetRelativePath(fileHolder.FullName, length); string relativePath = IPath.GetRelativePath(fileHolder.FullName, length);
sourceDirectory = Path.Combine(aPropertySingletonDirectory, sourceDirectoryName); string propertyLogicSourceDirectory = Path.GetFullPath(Path.Combine(aPropertySingletonDirectory, sourceDirectoryName));
propertyLogic.SetAngleBracketCollection(aResultsFullGroupDirectory, sourceDirectory); propertyLogic.SetAngleBracketCollection(aResultsFullGroupDirectory, propertyLogicSourceDirectory);
resize.SetAngleBracketCollection(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, sourceDirectory); resize.SetAngleBracketCollection(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, sourceDirectory);
item = new(sourceDirectoryFileHolder, relativePath, fileHolder, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, property, false, false, false); item = new(sourceDirectoryFileHolder, relativePath, fileHolder, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, property, false, false, false);
Assert.IsNotNull(item.ImageFileHolder); Assert.IsNotNull(item.ImageFileHolder);
if (item.Property is null) if (item.Property is null)
{ {
property = propertyLogic.GetProperty(item, subFileTuples, parseExceptions); Shared.Models.Methods.IBlurHasher? blurHasher = new BlurHash.Models.BlurHasher();
property = propertyLogic.GetProperty(blurHasher, item, subFileTuples, parseExceptions);
item.Update(property); item.Update(property);
} }
if (property is null || item.Property is null) if (property is null || item.Property is null)
@ -181,6 +181,7 @@ public class UnitTestResize
outputResolutionToResize = resize.GetResizeKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, subFileTuples, parseExceptions, metadataCollection, item.Property, mappingFromItem); outputResolutionToResize = resize.GetResizeKeyValuePairs(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, subFileTuples, parseExceptions, metadataCollection, item.Property, mappingFromItem);
Assert.IsNotNull(mappingFromItem.ResizedFileHolder); Assert.IsNotNull(mappingFromItem.ResizedFileHolder);
resize.SaveResizedSubfile(_Configuration.PropertyConfiguration, outputResolution, cResultsFullGroupDirectory, subFileTuples, item, item.Property, mappingFromItem, outputResolutionToResize); resize.SaveResizedSubfile(_Configuration.PropertyConfiguration, outputResolution, cResultsFullGroupDirectory, subFileTuples, item, item.Property, mappingFromItem, outputResolutionToResize);
NonThrowTryCatch();
} }
} }

View File

@ -27,19 +27,20 @@
<DefineConstants>Linux</DefineConstants> <DefineConstants>Linux</DefineConstants>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="coverlet.collector" Version="3.2.0" /> <PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" /> <PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" /> <PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" /> <PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\BlurHash\BlurHash.csproj" />
<ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" /> <ProjectReference Include="..\Shared\View-by-Distance.Shared.csproj" />
<ProjectReference Include="..\Property\Property.csproj" /> <ProjectReference Include="..\Property\Property.csproj" />
<ProjectReference Include="..\Metadata\Metadata.csproj" /> <ProjectReference Include="..\Metadata\Metadata.csproj" />

View File

@ -66,6 +66,13 @@ public class UnitTestFace
_PropertyConfiguration = propertyConfiguration; _PropertyConfiguration = propertyConfiguration;
} }
private static void NonThrowTryCatch()
{
try
{ throw new Exception(); }
catch (Exception) { }
}
[TestMethod] [TestMethod]
public void TestConfiguration() public void TestConfiguration()
{ {
@ -73,6 +80,7 @@ public class UnitTestFace
throw new Exception("Configuration has to match interface!"); throw new Exception("Configuration has to match interface!");
if (_Configuration.LocationFactor != Shared.Models.Stateless.ILocation.Factor) if (_Configuration.LocationFactor != Shared.Models.Stateless.ILocation.Factor)
throw new Exception("Configuration has to match interface!"); throw new Exception("Configuration has to match interface!");
NonThrowTryCatch();
} }
[TestMethod] [TestMethod]
@ -85,6 +93,7 @@ public class UnitTestFace
Assert.IsFalse(_WorkingDirectory is null); Assert.IsFalse(_WorkingDirectory is null);
Assert.IsFalse(_ConfigurationRoot is null); Assert.IsFalse(_ConfigurationRoot is null);
Assert.IsFalse(_PropertyConfiguration is null); Assert.IsFalse(_PropertyConfiguration is null);
NonThrowTryCatch();
} }
private A_Property GetPropertyLogic(bool reverse, string aResultsFullGroupDirectory) private A_Property GetPropertyLogic(bool reverse, string aResultsFullGroupDirectory)
@ -156,6 +165,7 @@ public class UnitTestFace
Assert.IsTrue(checkB > checkA); Assert.IsTrue(checkB > checkA);
int checkC = (int)(_Configuration.RangeDistanceTolerance[1] * DistanceFactor); int checkC = (int)(_Configuration.RangeDistanceTolerance[1] * DistanceFactor);
Assert.IsTrue(checkC == ToleranceAfterFactor); Assert.IsTrue(checkC == ToleranceAfterFactor);
NonThrowTryCatch();
} }
private (string, string) GetResultsFullGroupDirectories() private (string, string) GetResultsFullGroupDirectories()
@ -194,20 +204,8 @@ public class UnitTestFace
[TestMethod] [TestMethod]
public void TestMethodFace() public void TestMethodFace()
{ {
// string sourceFileName = "IMG_0067.jpg"; string sourceFileName = "640794601.jpg";
// string sourceDirectoryName = "Mackenzie Prom 2017"; string sourceDirectoryName = "Halloween 2006";
// string sourceFileName = "Fall 2005 (113).jpg";
// string sourceDirectoryName = "=2005.3 Fall";
// string sourceFileName = "DSCN0534.jpg";
// string sourceDirectoryName = "Logan Swimming Lessons 2013";
// string sourceFileName = "DSC_4913.jpg";
// string sourceDirectoryName = "Disneyland 2014";
// string sourceFileName = "Logan Michael Sept 08 (193).jpg";
// string sourceDirectoryName = "=2008.2 Summer Logan Michael";
// string sourceFileName = "Halloween 2006 (112).jpg";
// string sourceDirectoryName = "Halloween 2006";
string sourceFileName = "1384160978.jpg";
string sourceDirectoryName = "zzz Portrait Innovations Files 2007";
Item item; Item item;
bool reverse = false; bool reverse = false;
FileHolder resizedFileHolder; FileHolder resizedFileHolder;
@ -220,7 +218,6 @@ public class UnitTestFace
int length = _PropertyConfiguration.RootDirectory.Length; int length = _PropertyConfiguration.RootDirectory.Length;
string outputResolution = _Configuration.OutputResolutions[0]; string outputResolution = _Configuration.OutputResolutions[0];
(string cResultsFullGroupDirectory, _, _) = GetResultsFullGroupDirectories(outputResolution); (string cResultsFullGroupDirectory, _, _) = GetResultsFullGroupDirectories(outputResolution);
string sourceDirectory = Path.Combine(_PropertyConfiguration.RootDirectory, sourceDirectoryName);
(string aResultsFullGroupDirectory, string bResultsFullGroupDirectory) = GetResultsFullGroupDirectories(); (string aResultsFullGroupDirectory, string bResultsFullGroupDirectory) = GetResultsFullGroupDirectories();
_Logger.Information(_Configuration.ModelDirectory); _Logger.Information(_Configuration.ModelDirectory);
A_Property propertyLogic = GetPropertyLogic(reverse, aResultsFullGroupDirectory); A_Property propertyLogic = GetPropertyLogic(reverse, aResultsFullGroupDirectory);
@ -234,18 +231,19 @@ public class UnitTestFace
_ = resize.ToString(); _ = resize.ToString();
bool isUniqueFileName = false; bool isUniqueFileName = false;
bool? isNotUniqueAndNeedsReview = null; bool? isNotUniqueAndNeedsReview = null;
bool anyNullOrNoIsUniqueFileName = true;
FileHolder sourceDirectoryFileHolder = new(".json"); FileHolder sourceDirectoryFileHolder = new(".json");
string sourceDirectory = Path.GetFullPath(Path.Combine(_PropertyConfiguration.RootDirectory, sourceDirectoryName));
FileHolder fileHolder = new(Path.Combine(sourceDirectory, sourceFileName)); FileHolder fileHolder = new(Path.Combine(sourceDirectory, sourceFileName));
string relativePath = IPath.GetRelativePath(fileHolder.FullName, length); string relativePath = IPath.GetRelativePath(fileHolder.FullName, length);
sourceDirectory = Path.Combine(aPropertySingletonDirectory, sourceDirectoryName); string propertyLogicSourceDirectory = Path.GetFullPath(Path.Combine(aPropertySingletonDirectory, sourceDirectoryName));
propertyLogic.SetAngleBracketCollection(aResultsFullGroupDirectory, sourceDirectory, anyNullOrNoIsUniqueFileName); propertyLogic.SetAngleBracketCollection(aResultsFullGroupDirectory, propertyLogicSourceDirectory);
resize.SetAngleBracketCollection(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, sourceDirectory); resize.SetAngleBracketCollection(_Configuration.PropertyConfiguration, cResultsFullGroupDirectory, sourceDirectory);
item = new(sourceDirectoryFileHolder, relativePath, fileHolder, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, property, false, false, false); item = new(sourceDirectoryFileHolder, relativePath, fileHolder, isNotUniqueAndNeedsReview, isUniqueFileName, isValidImageFormatExtension, property, false, false, false);
Assert.IsNotNull(item.ImageFileHolder); Assert.IsNotNull(item.ImageFileHolder);
if (item.Property is null) if (item.Property is null)
{ {
property = propertyLogic.GetProperty(item, subFileTuples, parseExceptions); Shared.Models.Methods.IBlurHasher? blurHasher = new BlurHash.Models.BlurHasher();
property = propertyLogic.GetProperty(blurHasher, item, subFileTuples, parseExceptions);
item.Update(property); item.Update(property);
} }
if (property is null || item.Property is null) if (property is null || item.Property is null)
@ -268,6 +266,7 @@ public class UnitTestFace
List<FaceDistance> faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncodings[0]); List<FaceDistance> faceDistanceLengths = FaceRecognition.FaceDistances(faceDistanceEncodings, faceDistanceEncodings[0]);
Assert.IsTrue(faceDistanceLengths.Count == 2); Assert.IsTrue(faceDistanceLengths.Count == 2);
Assert.IsNotNull(sourceFileName); Assert.IsNotNull(sourceFileName);
NonThrowTryCatch();
} }
} }

View File

@ -3,6 +3,8 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16 # Visual Studio Version 16
VisualStudioVersion = 16.0.30114.105 VisualStudioVersion = 16.0.30114.105
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlurHash", "BlurHash\BlurHash.csproj", "{9689371E-F67C-4392-A636-C398D28C089B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Date-Group", "Date-Group\Date-Group.csproj", "{DFEDB5F9-AFFC-40A2-9FEC-9B84C83B63D9}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Date-Group", "Date-Group\Date-Group.csproj", "{DFEDB5F9-AFFC-40A2-9FEC-9B84C83B63D9}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Delete-By-Distinct", "Delete-By-Distinct\Delete-By-Distinct.csproj", "{3F00BDD5-75F8-470C-ACED-1A26FDC8D7B3}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Delete-By-Distinct", "Delete-By-Distinct\Delete-By-Distinct.csproj", "{3F00BDD5-75F8-470C-ACED-1A26FDC8D7B3}"
@ -13,6 +15,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Distance", "Distance\Distan
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Drag-Drop-Explorer", "Drag-Drop-Explorer\Drag-Drop-Explorer.csproj", "{986B009B-2937-4624-AC9C-13806868DB8C}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Drag-Drop-Explorer", "Drag-Drop-Explorer\Drag-Drop-Explorer.csproj", "{986B009B-2937-4624-AC9C-13806868DB8C}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Drag-Drop-Move", "Drag-Drop-Move\Drag-Drop-Move.csproj", "{CF05EFAC-C212-4EE0-A644-3F728991AA54}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Drag-Drop-Search", "Drag-Drop-Search\Drag-Drop-Search.csproj", "{87EB76BC-32A9-4FD0-922A-BD7E9B6E7D8B}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Drag-Drop-Search", "Drag-Drop-Search\Drag-Drop-Search.csproj", "{87EB76BC-32A9-4FD0-922A-BD7E9B6E7D8B}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicate-Search", "Duplicate-Search\Duplicate-Search.csproj", "{48E87D9B-B802-467A-BDC7-E86F7FD01D5C}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicate-Search", "Duplicate-Search\Duplicate-Search.csproj", "{48E87D9B-B802-467A-BDC7-E86F7FD01D5C}"
@ -29,6 +33,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Map", "Map\Map.csproj", "{9
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Metadata", "Metadata\Metadata.csproj", "{961D11A0-44C8-48CD-BEEE-A6E6903AE58F}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Metadata", "Metadata\Metadata.csproj", "{961D11A0-44C8-48CD-BEEE-A6E6903AE58F}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Move-By-Id", "Move-By-Id\Move-By-Id.csproj", "{0FDFBC71-3801-483F-A4AC-CC8CF857D54F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Person", "Person\Person.csproj", "{C5003A39-334B-444B-9873-39B26E58D667}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhotoPrism", "PhotoPrism\PhotoPrism.csproj", "{DF4B0776-E0E5-4220-8721-8D1E491FF263}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhotoPrism", "PhotoPrism\PhotoPrism.csproj", "{DF4B0776-E0E5-4220-8721-8D1E491FF263}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrepareForOld", "PrepareForOld\PrepareForOld.csproj", "{F73F9468-0139-4B05-99CE-C6C0403D03E5}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrepareForOld", "PrepareForOld\PrepareForOld.csproj", "{F73F9468-0139-4B05-99CE-C6C0403D03E5}"
@ -47,12 +55,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestsWithFaceRecognitionDot
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "View-by-Distance.Shared", "shared\View-by-Distance.Shared.csproj", "{1D231660-33B4-4763-9C9F-C6ACC8BA600D}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "View-by-Distance.Shared", "shared\View-by-Distance.Shared.csproj", "{1D231660-33B4-4763-9C9F-C6ACC8BA600D}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Move-By-Id", "Move-By-Id\Move-By-Id.csproj", "{0FDFBC71-3801-483F-A4AC-CC8CF857D54F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Person", "Person\Person.csproj", "{C5003A39-334B-444B-9873-39B26E58D667}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Drag-Drop-Move", "Drag-Drop-Move\Drag-Drop-Move.csproj", "{CF05EFAC-C212-4EE0-A644-3F728991AA54}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -166,5 +168,9 @@ Global
{CF05EFAC-C212-4EE0-A644-3F728991AA54}.Debug|Any CPU.Build.0 = Debug|Any CPU {CF05EFAC-C212-4EE0-A644-3F728991AA54}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CF05EFAC-C212-4EE0-A644-3F728991AA54}.Release|Any CPU.ActiveCfg = Release|Any CPU {CF05EFAC-C212-4EE0-A644-3F728991AA54}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CF05EFAC-C212-4EE0-A644-3F728991AA54}.Release|Any CPU.Build.0 = Release|Any CPU {CF05EFAC-C212-4EE0-A644-3F728991AA54}.Release|Any CPU.Build.0 = Release|Any CPU
{9689371E-F67C-4392-A636-C398D28C089B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9689371E-F67C-4392-A636-C398D28C089B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9689371E-F67C-4392-A636-C398D28C089B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9689371E-F67C-4392-A636-C398D28C089B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal