Browse Source

Semaphore for image resizing.

pull/577/head
Sebastian 5 years ago
parent
commit
d4bcc495c8
  1. 124
      backend/src/Squidex.Infrastructure/Assets/ImageSharp/ImageSharpAssetThumbnailGenerator.cs

124
backend/src/Squidex.Infrastructure/Assets/ImageSharp/ImageSharpAssetThumbnailGenerator.cs

@ -7,6 +7,7 @@
using System; using System;
using System.IO; using System.IO;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp; using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg;
@ -19,76 +20,89 @@ namespace Squidex.Infrastructure.Assets.ImageSharp
{ {
public sealed class ImageSharpAssetThumbnailGenerator : IAssetThumbnailGenerator public sealed class ImageSharpAssetThumbnailGenerator : IAssetThumbnailGenerator
{ {
public Task CreateThumbnailAsync(Stream source, Stream destination, ResizeOptions options) private readonly SemaphoreSlim semaphoreSlim = new SemaphoreSlim(Math.Max(Environment.ProcessorCount / 4, 1));
public async Task CreateThumbnailAsync(Stream source, Stream destination, ResizeOptions options)
{ {
Guard.NotNull(source, nameof(source));
Guard.NotNull(destination, nameof(destination));
Guard.NotNull(options, nameof(options)); Guard.NotNull(options, nameof(options));
if (!options.IsValid) if (!options.IsValid)
{ {
source.CopyTo(destination); source.CopyTo(destination);
return Task.CompletedTask; return;
} }
var w = options.Width ?? 0; var w = options.Width ?? 0;
var h = options.Height ?? 0; var h = options.Height ?? 0;
using (var image = Image.Load(source, out var format)) await semaphoreSlim.WaitAsync();
{
var encoder = Configuration.Default.ImageFormatsManager.FindEncoder(format);
if (encoder == null)
{
throw new NotSupportedException();
}
if (options.Quality.HasValue && (encoder is JpegEncoder || !options.KeepFormat))
{
encoder = new JpegEncoder { Quality = options.Quality.Value };
}
image.Mutate(x => x.AutoOrient()); try
{
if (w > 0 || h > 0) using (var image = Image.Load(source, out var format))
{ {
var isCropUpsize = options.Mode == ResizeMode.CropUpsize; var encoder = Configuration.Default.ImageFormatsManager.FindEncoder(format);
if (!Enum.TryParse<ISResizeMode>(options.Mode.ToString(), true, out var resizeMode)) if (encoder == null)
{ {
resizeMode = ISResizeMode.Max; throw new NotSupportedException();
} }
if (isCropUpsize) if (options.Quality.HasValue && (encoder is JpegEncoder || !options.KeepFormat))
{ {
resizeMode = ISResizeMode.Crop; encoder = new JpegEncoder { Quality = options.Quality.Value };
} }
if (w >= image.Width && h >= image.Height && resizeMode == ISResizeMode.Crop && !isCropUpsize) image.Mutate(x => x.AutoOrient());
{
resizeMode = ISResizeMode.BoxPad;
}
var resizeOptions = new ISResizeOptions { Size = new Size(w, h), Mode = resizeMode };
if (options.FocusX.HasValue && options.FocusY.HasValue) if (w > 0 || h > 0)
{ {
resizeOptions.CenterCoordinates = new PointF( var isCropUpsize = options.Mode == ResizeMode.CropUpsize;
+(options.FocusX.Value / 2f) + 0.5f,
-(options.FocusY.Value / 2f) + 0.5f if (!Enum.TryParse<ISResizeMode>(options.Mode.ToString(), true, out var resizeMode))
); {
resizeMode = ISResizeMode.Max;
}
if (isCropUpsize)
{
resizeMode = ISResizeMode.Crop;
}
if (w >= image.Width && h >= image.Height && resizeMode == ISResizeMode.Crop && !isCropUpsize)
{
resizeMode = ISResizeMode.BoxPad;
}
var resizeOptions = new ISResizeOptions { Size = new Size(w, h), Mode = resizeMode };
if (options.FocusX.HasValue && options.FocusY.HasValue)
{
resizeOptions.CenterCoordinates = new PointF(
+(options.FocusX.Value / 2f) + 0.5f,
-(options.FocusY.Value / 2f) + 0.5f
);
}
image.Mutate(x => x.Resize(resizeOptions));
} }
image.Mutate(x => x.Resize(resizeOptions)); image.Save(destination, encoder);
} }
image.Save(destination, encoder);
} }
finally
return Task.CompletedTask; {
semaphoreSlim.Release();
}
} }
public Task<ImageInfo?> GetImageInfoAsync(Stream source) public Task<ImageInfo?> GetImageInfoAsync(Stream source)
{ {
Guard.NotNull(source, nameof(source));
ImageInfo? result = null; ImageInfo? result = null;
try try
@ -108,22 +122,34 @@ namespace Squidex.Infrastructure.Assets.ImageSharp
return Task.FromResult(result); return Task.FromResult(result);
} }
public Task<ImageInfo> FixOrientationAsync(Stream source, Stream destination) public async Task<ImageInfo> FixOrientationAsync(Stream source, Stream destination)
{ {
using (var image = Image.Load(source, out var format)) Guard.NotNull(source, nameof(source));
{ Guard.NotNull(destination, nameof(destination));
var encoder = Configuration.Default.ImageFormatsManager.FindEncoder(format);
await semaphoreSlim.WaitAsync();
if (encoder == null) try
{
using (var image = Image.Load(source, out var format))
{ {
throw new NotSupportedException(); var encoder = Configuration.Default.ImageFormatsManager.FindEncoder(format);
}
if (encoder == null)
{
throw new NotSupportedException();
}
image.Mutate(x => x.AutoOrient()); image.Mutate(x => x.AutoOrient());
image.Save(destination, encoder); image.Save(destination, encoder);
return Task.FromResult(GetImageInfo(image)); return GetImageInfo(image);
}
}
finally
{
semaphoreSlim.Release();
} }
} }

Loading…
Cancel
Save