diff --git a/.DS_Store b/.DS_Store
index 0040be41..01228294 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/Damselfly.Core.ImageProcessing/Damselfly.Core.ImageProcessing.csproj b/Damselfly.Core.ImageProcessing/Damselfly.Core.ImageProcessing.csproj
index f4c6a3a8..ac47c334 100644
--- a/Damselfly.Core.ImageProcessing/Damselfly.Core.ImageProcessing.csproj
+++ b/Damselfly.Core.ImageProcessing/Damselfly.Core.ImageProcessing.csproj
@@ -15,6 +15,7 @@
+
diff --git a/Damselfly.Core.ImageProcessing/ImageMagickProcessor.cs b/Damselfly.Core.ImageProcessing/ImageMagickProcessor.cs
index 10fbde29..997f5f95 100644
--- a/Damselfly.Core.ImageProcessing/ImageMagickProcessor.cs
+++ b/Damselfly.Core.ImageProcessing/ImageMagickProcessor.cs
@@ -11,7 +11,6 @@ public class ImageMagickProcessor : IImageProcessor
private const string graphicsMagickExe = "gm";
- // SkiaSharp doesn't handle .heic files... yet
private static readonly string[] s_imageExtensions = { ".jpg", ".jpeg", ".png", ".heic", ".tif", ".tiff", ".webp", ".arw", ".cr3" };
private static bool imAvailable;
private readonly bool s_useGraphicsMagick = false; // GM doesn't support HEIC yet.
diff --git a/Damselfly.Core.ImageProcessing/ImageProcessorFactory.cs b/Damselfly.Core.ImageProcessing/ImageProcessorFactory.cs
index 913ee880..27ee54f7 100644
--- a/Damselfly.Core.ImageProcessing/ImageProcessorFactory.cs
+++ b/Damselfly.Core.ImageProcessing/ImageProcessorFactory.cs
@@ -7,12 +7,14 @@ public class ImageProcessorFactory : IImageProcessorFactory
private readonly ImageMagickProcessor imProcessor;
private readonly ImageSharpProcessor isharpProcessor;
private readonly SkiaSharpProcessor skiaProcessor;
+ private readonly MagickNetProcessor magickNetProcessor;
public ImageProcessorFactory()
{
skiaProcessor = new SkiaSharpProcessor();
isharpProcessor = new ImageSharpProcessor();
imProcessor = new ImageMagickProcessor();
+ magickNetProcessor = new MagickNetProcessor();
}
public void SetContentPath(string path)
@@ -47,11 +49,17 @@ public IHashProvider GetHashProvider()
if ( ImageSharpProcessor.SupportedFileExtensions.Any(x =>
x.Equals(fileExtension, StringComparison.OrdinalIgnoreCase)) ) return isharpProcessor;
+ // Magick.Net - As of 12-Aug-2024, it can do thumbs for 100 images in about 45 seconds.
+ // Main advantage: it can also handle HEIC, and is native
+ if ( MagickNetProcessor.SupportedFileExtensions.Any(x =>
+ x.Equals(fileExtension, StringComparison.OrdinalIgnoreCase)) ) return magickNetProcessor;
+
// ImageMagick last, because of the complexities of spawning a child process.
// As of 12-Aug-2021, it can do thumbs for 100 images in about 33 seconds.
// Main advantage: it can also handle HEIC
- if ( ImageMagickProcessor.SupportedFileExtensions.Any(x =>
- x.Equals(fileExtension, StringComparison.OrdinalIgnoreCase)) ) return imProcessor;
+ // Mar 2024 - disable this in preference to Magick.Net
+ //if ( ImageMagickProcessor.SupportedFileExtensions.Any(x =>
+ // x.Equals(fileExtension, StringComparison.OrdinalIgnoreCase)) ) return imProcessor;
return null;
}
diff --git a/Damselfly.Core.ImageProcessing/MagickNetProcessor.cs b/Damselfly.Core.ImageProcessing/MagickNetProcessor.cs
new file mode 100644
index 00000000..528538b0
--- /dev/null
+++ b/Damselfly.Core.ImageProcessing/MagickNetProcessor.cs
@@ -0,0 +1,93 @@
+using Damselfly.Core.DbModels.Images;
+using Damselfly.Core.Interfaces;
+using Damselfly.Core.Utils;
+using Damselfly.Shared.Utils;
+using ImageMagick;
+
+namespace Damselfly.Core.ImageProcessing;
+
+public class MagickNetProcessor : IImageProcessor
+{
+ public static ICollection SupportedFileExtensions => SupportedExtensions();
+
+ private static ICollection SupportedExtensions()
+ {
+ // Interrogate Magick.Net for a list of supported file extensions where we can read and write the image
+ var formats = MagickNET.SupportedFormats.Where( format => format.SupportsReading && format.SupportsWriting )
+ .Select( format => $".{format.Format.ToString().ToLower()}").ToList();
+
+ return formats;
+ }
+
+ ///
+ /// Convert the files to thumbnails using Magick.Net
+ ///
+ /// Source.
+ /// Sizes.
+ public async Task CreateThumbs(FileInfo source, IDictionary destFiles)
+ {
+ // This processor doesn't support hash creation
+ IImageProcessResult result = new ImageProcessResult { ThumbsGenerated = false, ImageHash = string.Empty };
+
+ using var image = new MagickImage();
+
+ var load = new Stopwatch("MagickNetLoad");
+
+ await image.ReadAsync(source.FullName);
+ image.AutoOrient();
+
+ load.Stop();
+
+ var thumbs = new Stopwatch("MagickNetThumbs");
+
+ foreach ( var pair in destFiles )
+ {
+ var dest = pair.Key;
+ var config = pair.Value;
+
+ var targetRatio = (decimal)config.width / (decimal)config.height;
+ var currentRatio = (decimal)image.Width/(decimal)image.Height;
+
+ bool widthIsLongest = currentRatio > targetRatio;
+
+ var intermediateSize = widthIsLongest
+ ? new MagickGeometry { Width = (int)(config.height * currentRatio), Height = config.height }
+ : new MagickGeometry { Width = config.width, Height = (int)(config.width / currentRatio) };
+
+ Logging.LogTrace("Generating thumbnail for {0}: {1}x{2}", source.Name, config.width, config.height);
+
+ image.Resize(intermediateSize);
+ intermediateSize.IgnoreAspectRatio = false;
+
+ if( currentRatio != targetRatio && config.cropToRatio)
+ {
+ var size = new MagickGeometry(config.width, config.height);
+
+ image.Crop(size, Gravity.Center);
+ }
+
+ await image.WriteAsync(dest.FullName);
+
+ result.ThumbsGenerated = true;
+ }
+
+ thumbs.Stop();
+
+ return result;
+ }
+
+ public Task TransformDownloadImage(string input, Stream output, IExportSettings config)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task GetCroppedFile(FileInfo source, int x, int y, int width, int height, FileInfo destFile)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task CropImage(FileInfo source, int x, int y, int width, int height, Stream stream)
+ {
+ throw new NotImplementedException();
+ }
+}
\ No newline at end of file
diff --git a/Damselfly.Web.Client/Pages/ImagePage.razor b/Damselfly.Web.Client/Pages/ImagePage.razor
index 41e6bb6a..bbb68392 100644
--- a/Damselfly.Web.Client/Pages/ImagePage.razor
+++ b/Damselfly.Web.Client/Pages/ImagePage.razor
@@ -212,6 +212,7 @@
CurrentImage = await imageCache.GetCachedImage(imageId);
navContext.CurrentImage = CurrentImage;
+ // TODO: Fix nullref here
ImageUrl = CurrentImage.ThumbUrl(ThumbSize.Medium);
ImageUrlHighRes = CurrentImage.ThumbUrl(ThumbSize.ExtraLarge);
;
diff --git a/Damselfly.Web.Client/wwwroot/version.js b/Damselfly.Web.Client/wwwroot/version.js
index dae24d53..070aaaa9 100644
--- a/Damselfly.Web.Client/wwwroot/version.js
+++ b/Damselfly.Web.Client/wwwroot/version.js
@@ -1 +1 @@
-const CACHE_VERSION='4.1.3-20240321104506'
+const CACHE_VERSION='4.1.3-20240326071412'
diff --git a/Damselfly.Web.Server/Controllers/PeopleController.cs b/Damselfly.Web.Server/Controllers/PeopleController.cs
index a8f539dc..038e0df8 100644
--- a/Damselfly.Web.Server/Controllers/PeopleController.cs
+++ b/Damselfly.Web.Server/Controllers/PeopleController.cs
@@ -14,9 +14,7 @@ namespace Damselfly.Web.Server.Controllers;
[ApiController]
[Route("/api/people")]
public class PeopleController( ImageRecognitionService _aiService,
- IPeopleService _peopleService,
- ILogger _logger,
- ImageCache _imageCache) : ControllerBase
+ IPeopleService _peopleService) : ControllerBase
{
[HttpGet("/api/person/{personId}")]
public async Task GetPerson( int personId )
diff --git a/Damselfly.Web.Server/Controllers/StaticDataController.cs b/Damselfly.Web.Server/Controllers/StaticDataController.cs
index a9498da1..fc2527c7 100644
--- a/Damselfly.Web.Server/Controllers/StaticDataController.cs
+++ b/Damselfly.Web.Server/Controllers/StaticDataController.cs
@@ -12,8 +12,7 @@ namespace Damselfly.Web.Server.Controllers;
//[Authorize(Policy = PolicyDefinitions.s_IsLoggedIn)]
[ApiController]
[Route("/api/data")]
-public class StaticDataController( ILogger _logger,
- MetaDataService _metaDataService,
+public class StaticDataController( MetaDataService _metaDataService,
ICachedDataService _cachedData,
StatisticsService _stats) : ControllerBase
{
diff --git a/Directory.Packages.props b/Directory.Packages.props
index a958b666..cbc5dda1 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -20,6 +20,7 @@
+