diff --git a/zero/Media/ImageSharp/Processors/BlurWebProcessor.cs b/zero/Media/ImageSharp/Processors/BlurWebProcessor.cs
new file mode 100644
index 00000000..ddb5e49f
--- /dev/null
+++ b/zero/Media/ImageSharp/Processors/BlurWebProcessor.cs
@@ -0,0 +1,48 @@
+using Microsoft.Extensions.Logging;
+using SixLabors.ImageSharp.Processing;
+using SixLabors.ImageSharp.Web;
+using SixLabors.ImageSharp.Web.Commands;
+using SixLabors.ImageSharp.Web.Processors;
+using System.Globalization;
+
+namespace zero.Media.ImageSharp.Processors;
+
+public class BlurWebProcessor : IImageWebProcessor
+{
+ //
+ /// The command constant for the gaussian blur sigma.
+ ///
+ public const string Blur = "blur";
+
+ ///
+ /// The reusable collection of commands.
+ ///
+ private static readonly IEnumerable BlurCommands = new[] { Blur };
+
+ ///
+ public IEnumerable Commands { get; } = BlurCommands;
+
+ ///
+ public FormattedImage Process(
+ FormattedImage image,
+ ILogger logger,
+ CommandCollection commands,
+ CommandParser parser,
+ CultureInfo culture)
+ {
+ if (commands.Contains(Blur))
+ {
+ float sigma = parser.ParseValue(commands.GetValueOrDefault(Blur), culture);
+
+ if (sigma != 0)
+ {
+ image.Image.Mutate(x => x.GaussianBlur(sigma));
+ }
+ }
+
+ return image;
+ }
+
+ ///
+ public bool RequiresTrueColorPixelFormat(CommandCollection commands, CommandParser parser, CultureInfo culture) => true;
+}
diff --git a/zero/Media/Indexes/Media_ByChildren.cs b/zero/Media/Indexes/Media_ByChildren.cs
deleted file mode 100644
index 0f32893b..00000000
--- a/zero/Media/Indexes/Media_ByChildren.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-// using Raven.Client.Documents.Indexes;
-//
-// namespace zero.Media;
-//
-// public class Media_ByChildren : ZeroMultiMapIndex
-// {
-// public class Result : ZeroIdEntity, ISupportsDbConventions
-// {
-// public string ParentId { get; set; }
-//
-// public int ChildrenCount { get; set; }
-//
-// public string[] ChildrenIds { get; set; }
-// }
-//
-//
-// protected override void Create()
-// {
-// AddMap(items => items.Select(item => new Result()
-// {
-// Id = item.Id,
-// ParentId = item.ParentId,
-// ChildrenCount = 1,
-// ChildrenIds = new string[] { }
-// }));
-//
-// Reduce = results => results.GroupBy(x => new { x.ParentId }).Select(group => new Result()
-// {
-// Id = null,
-// ParentId = group.Key.ParentId,
-// ChildrenCount = group.Sum(x => x.ChildrenCount),
-// ChildrenIds = group.Select(x => x.Id).ToArray()
-// });
-//
-// StoreAllFields(FieldStorage.Yes);
-// Index(x => x.ParentId, FieldIndexing.Exact);
-// }
-// }
\ No newline at end of file
diff --git a/zero/Media/Indexes/Media_ByHierarchy.cs b/zero/Media/Indexes/Media_ByHierarchy.cs
deleted file mode 100644
index 46ce620a..00000000
--- a/zero/Media/Indexes/Media_ByHierarchy.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-// using Raven.Client.Documents.Indexes;
-//
-// namespace zero.Media;
-//
-// public class Media_ByHierarchy : ZeroIndex
-// {
-// public class Result : ZeroIdEntity, ISupportsDbConventions
-// {
-// public string Name { get; set; }
-//
-// public List Path { get; set; } = new List();
-//
-// public string[] PathIds { get; set; } = Array.Empty();
-// }
-//
-//
-// public class PathResult
-// {
-// public string Id { get; set; }
-//
-// public string Name { get; set; }
-// }
-//
-//
-// protected override void Create()
-// {
-// Map = items => items
-// .Select(item => new
-// {
-// Item = item,
-// Path = Recurse(item, x => LoadDocument(x.ParentId)).Where(x => x != null && x.Id != null && x.Id != item.Id).Reverse()
-// })
-// .Select(item => new Result
-// {
-// Id = item.Item.Id,
-// Name = item.Item.Name,
-// Path = item.Path.Select(current => new PathResult() { Id = current.Id, Name = current.Name }).ToList(),
-// PathIds = item.Path.Select(current => current.Id).ToArray()
-// });
-//
-// StoreAllFields(FieldStorage.Yes);
-// Index("PathIds", FieldIndexing.Exact);
-// //Index(x => x.ChannelId, FieldIndexing.Exact);
-// }
-// }
diff --git a/zero/Media/MediaCreator.cs b/zero/Media/MediaCreator.cs
index 16751620..04c00f02 100644
--- a/zero/Media/MediaCreator.cs
+++ b/zero/Media/MediaCreator.cs
@@ -1,6 +1,9 @@
using SixLabors.ImageSharp;
+using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Png;
+using SixLabors.ImageSharp.Formats.Webp;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
@@ -61,6 +64,7 @@ public class MediaCreator : IMediaCreator
if (isImage)
{
+ // load image to create thumbnails
using Image image = await Image.LoadAsync(fileInfo.AbsolutePath, cancellationToken);
model.Metadata = GetImageMetadata(image.Metadata, image.Size);
@@ -68,17 +72,22 @@ public class MediaCreator : IMediaCreator
if (Options.Thumbnails != null)
{
- foreach ((string key, ResizeOptions opts) in Options.Thumbnails)
+ foreach ((string key, ThumbnailOptions opts) in Options.Thumbnails)
{
Image imageFrame = image.Frames.Count > 1 ? image.Frames.CloneFrame(0) : image.Clone();
- imageFrame.Mutate(x => x.Resize(opts));
+ IImageEncoder encoder = opts.Encoder ?? new WebpEncoder();
+
+ if (opts.Mutate != null)
+ {
+ imageFrame.Mutate(opts.Mutate);
+ }
using MemoryStream stream = new();
- await imageFrame.SaveAsync(stream, new PngEncoder(), cancellationToken);
+ await imageFrame.SaveAsync(stream, encoder, cancellationToken);
stream.Position = 0;
- string thumbFilename = normalizedFilename.TrimEnd(extension) + "." + Safenames.File(key) + ".png";
+ string thumbFilename = normalizedFilename.TrimEnd(extension) + "." + Safenames.File(key) + opts.Extension.Or(".webp");
string path = directory + '/' + thumbFilename;
await FileSystem.CreateFile(path, stream, cancellationToken: cancellationToken);
diff --git a/zero/Media/MediaOptions.cs b/zero/Media/MediaOptions.cs
index c74e48a7..a8a74905 100644
--- a/zero/Media/MediaOptions.cs
+++ b/zero/Media/MediaOptions.cs
@@ -1,11 +1,13 @@
-using SixLabors.ImageSharp.Processing;
+using SixLabors.ImageSharp.Formats;
+using SixLabors.ImageSharp.Formats.Png;
+using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Web.Caching;
namespace zero.Media;
public class MediaOptions
{
- public string FolderPath { get; set; }
+ public string FolderPath { get; set; } = string.Empty;
public string PublicPathPrefix { get; set; } = string.Empty;
@@ -13,7 +15,7 @@ public class MediaOptions
public List AllowedImageFileExtensions { get; set; }
- public Dictionary Thumbnails { get; set; }
+ public Dictionary Thumbnails { get; set; }
public ImageSharpOptions ImageSharp { get; set; } = new();
}
@@ -40,4 +42,14 @@ public class ImagingSharpRemoteCacheOptions
public string MediaFolder { get; set; } = "/media/_remote/";
public string KeyMapFile { get; set; } = "/Config/remotekeys.json";
+}
+
+
+public class ThumbnailOptions
+{
+ public string Extension { get; set; }
+
+ public IImageEncoder Encoder { get; set; }
+
+ public Action Mutate { get; set; }
}
\ No newline at end of file
diff --git a/zero/Media/ZeroMediaModule.cs b/zero/Media/ZeroMediaModule.cs
index 9eaf369c..60c258d8 100644
--- a/zero/Media/ZeroMediaModule.cs
+++ b/zero/Media/ZeroMediaModule.cs
@@ -22,7 +22,13 @@ internal class ZeroMediaModule : ZeroModule
.AddProvider()
.AddProcessor()
.AddProcessor()
- .Configure(configuration.GetSection("Zero:Media:ImageSharp:Cache"));
+ .AddProcessor();
+
+ services.AddOptions().Configure(opts =>
+ {
+ opts.CacheRootPath = "~/";
+ opts.CacheFolder = "cache";
+ }).Bind(configuration.GetSection("Zero:Media:ImageSharp:Cache"));
//configuration.AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), "Config/imaging.json"), true, true);
//configuration.AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), $"Config/imaging.{builder.Environment.EnvironmentName}.json"), true);