2021-07-08 13:48:44 +02:00
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Globalization;
|
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
using SixLabors.ImageSharp;
|
|
|
|
|
using SixLabors.ImageSharp.Processing;
|
|
|
|
|
using SixLabors.ImageSharp.Web;
|
|
|
|
|
using SixLabors.ImageSharp.Web.Commands;
|
|
|
|
|
using SixLabors.ImageSharp.Web.Processors;
|
|
|
|
|
|
|
|
|
|
namespace Umbraco.Cms.Web.Common.ImageProcessors
|
|
|
|
|
{
|
2021-08-06 12:59:23 +02:00
|
|
|
/// <summary>
|
|
|
|
|
/// Allows the cropping of images.
|
|
|
|
|
/// </summary>
|
2021-07-08 13:48:44 +02:00
|
|
|
public class CropWebProcessor : IImageWebProcessor
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
2021-08-06 12:59:23 +02:00
|
|
|
/// The command constant for the crop definition.
|
2021-07-08 13:48:44 +02:00
|
|
|
/// </summary>
|
|
|
|
|
public const string Crop = "crop";
|
|
|
|
|
|
2021-08-06 12:59:23 +02:00
|
|
|
/// <summary>
|
|
|
|
|
/// The command constant for the crop mode.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public const string Mode = "cropmode";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
|
public IEnumerable<string> Commands { get; } = new[]
|
2021-07-08 13:48:44 +02:00
|
|
|
{
|
2021-08-06 12:59:23 +02:00
|
|
|
Crop,
|
|
|
|
|
Mode
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
|
public FormattedImage Process(FormattedImage image, ILogger logger, IDictionary<string, string> commands, CommandParser parser, CultureInfo culture)
|
|
|
|
|
{
|
|
|
|
|
if (GetCrop(commands, parser, culture) is RectangleF crop)
|
2021-07-08 13:48:44 +02:00
|
|
|
{
|
2021-08-06 12:59:23 +02:00
|
|
|
Size size = image.Image.Size();
|
2021-08-09 12:00:37 +02:00
|
|
|
CropMode mode = GetMode(commands, parser, culture);
|
2021-08-06 12:59:23 +02:00
|
|
|
|
2021-08-09 12:00:37 +02:00
|
|
|
if (mode == CropMode.Percentage)
|
2021-08-06 12:59:23 +02:00
|
|
|
{
|
2021-08-09 12:00:37 +02:00
|
|
|
// Convert the percentage based model of left, top, right, bottom to x, y, width, height
|
|
|
|
|
float x = crop.Left * size.Width;
|
|
|
|
|
float y = crop.Top * size.Height;
|
|
|
|
|
float width = crop.Right < 1 ? (1 - crop.Left - crop.Right) * size.Width : size.Width;
|
|
|
|
|
float height = crop.Bottom < 1 ? (1 - crop.Top - crop.Bottom) * size.Height : size.Height;
|
2021-08-06 12:59:23 +02:00
|
|
|
|
2021-08-09 12:00:37 +02:00
|
|
|
crop = new RectangleF(x, y, width, height);
|
2021-08-06 12:59:23 +02:00
|
|
|
}
|
|
|
|
|
|
2021-08-09 12:00:37 +02:00
|
|
|
// Round and validate/clamp crop rectangle
|
|
|
|
|
var cropRectangle = Rectangle.Round(crop);
|
|
|
|
|
if (cropRectangle.X < size.Width && cropRectangle.Y < size.Height)
|
2021-08-06 12:59:23 +02:00
|
|
|
{
|
2021-08-09 12:00:37 +02:00
|
|
|
if (cropRectangle.Width > (size.Width - cropRectangle.X))
|
2021-08-06 12:59:23 +02:00
|
|
|
{
|
2021-08-09 12:00:37 +02:00
|
|
|
cropRectangle.Width = size.Width - cropRectangle.X;
|
2021-08-06 12:59:23 +02:00
|
|
|
}
|
|
|
|
|
|
2021-08-09 12:00:37 +02:00
|
|
|
if (cropRectangle.Height > (size.Height - cropRectangle.Y))
|
2021-08-06 12:59:23 +02:00
|
|
|
{
|
2021-08-09 12:00:37 +02:00
|
|
|
cropRectangle.Height = size.Height - cropRectangle.Y;
|
2021-08-06 12:59:23 +02:00
|
|
|
}
|
|
|
|
|
|
2021-08-09 12:00:37 +02:00
|
|
|
image.Image.Mutate(x => x.Crop(cropRectangle));
|
2021-08-06 12:59:23 +02:00
|
|
|
}
|
2021-07-08 13:48:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return image;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-06 12:59:23 +02:00
|
|
|
private static RectangleF? GetCrop(IDictionary<string, string> commands, CommandParser parser, CultureInfo culture)
|
2021-07-08 13:48:44 +02:00
|
|
|
{
|
2021-08-09 12:00:37 +02:00
|
|
|
float[] coordinates = parser.ParseValue<float[]>(commands.GetValueOrDefault(Crop), culture);
|
|
|
|
|
|
|
|
|
|
if (coordinates.Length != 4)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2021-08-06 12:59:23 +02:00
|
|
|
|
2021-08-09 12:00:37 +02:00
|
|
|
return new RectangleF(coordinates[0], coordinates[1], coordinates[2], coordinates[3]);
|
2021-07-08 13:48:44 +02:00
|
|
|
}
|
|
|
|
|
|
2021-08-06 12:59:23 +02:00
|
|
|
private static CropMode GetMode(IDictionary<string, string> commands, CommandParser parser, CultureInfo culture)
|
|
|
|
|
=> parser.ParseValue<CropMode>(commands.GetValueOrDefault(Mode), culture);
|
|
|
|
|
}
|
2021-07-08 13:48:44 +02:00
|
|
|
}
|