v10: Update to ImageSharp v2 (#12185)
* Update to ImageSharp 2.1.0 and ImageSharp.Web 2.0.0-alpha.0.23 * Rename CachedNameLength to CacheHashLength and add CacheFolderDepth setting * Replace PhysicalFileSystemProvider with WebRootImageProvider * Support EXIF-orientation in image dimention extractor * Remove virtual methods on FileProviderImageProvider * Simplify FileInfoImageResolver * Update to SixLabors.ImageSharp.Web 2.0.0-alpha.0.25 and remove custom providers * Make CropWebProcessor EXIF orientation-aware * Improve width/height sanitization * Also use 'v' as cache buster value * Add WebP to supported image file types * Update to SixLabors.ImageSharp.Web 2.0.0-alpha.0.27 and fix test * Fix rounding error and add test cases * Update to newest and stable releases * Move ImageSharpImageUrlGenerator to Umbraco.Web.Common * Use IConfigureOptions to configure ImageSharp options * Implement IEquatable on ImageUrlGenerationOptions classes * Fix empty/null values in image URL generation and corresponding tests * Use IsSupportedImageFormat extension method * Remove unneeded reflection
This commit is contained in:
@@ -201,7 +201,6 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
// Add default ImageSharp configuration and service implementations
|
||||
builder.Services.AddSingleton(SixLabors.ImageSharp.Configuration.Default);
|
||||
builder.Services.AddSingleton<IImageDimensionExtractor, ImageSharpDimensionExtractor>();
|
||||
builder.Services.AddSingleton<IImageUrlGenerator, ImageSharpImageUrlGenerator>();
|
||||
|
||||
builder.Services.AddSingleton<PackageDataInstallation>();
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
|
||||
using Umbraco.Cms.Core.Media;
|
||||
using Size = System.Drawing.Size;
|
||||
|
||||
@@ -30,10 +32,40 @@ namespace Umbraco.Cms.Infrastructure.Media
|
||||
IImageInfo imageInfo = Image.Identify(_configuration, stream);
|
||||
if (imageInfo != null)
|
||||
{
|
||||
size = new Size(imageInfo.Width, imageInfo.Height);
|
||||
size = IsExifOrientationRotated(imageInfo)
|
||||
? new Size(imageInfo.Height, imageInfo.Width)
|
||||
: new Size(imageInfo.Width, imageInfo.Height);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
private static bool IsExifOrientationRotated(IImageInfo imageInfo)
|
||||
=> GetExifOrientation(imageInfo) switch
|
||||
{
|
||||
ExifOrientationMode.LeftTop
|
||||
or ExifOrientationMode.RightTop
|
||||
or ExifOrientationMode.RightBottom
|
||||
or ExifOrientationMode.LeftBottom => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
private static ushort GetExifOrientation(IImageInfo imageInfo)
|
||||
{
|
||||
IExifValue<ushort> orientation = imageInfo.Metadata.ExifProfile?.GetValue(ExifTag.Orientation);
|
||||
if (orientation is not null)
|
||||
{
|
||||
if (orientation.DataType == ExifDataType.Short)
|
||||
{
|
||||
return orientation.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Convert.ToUInt16(orientation.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return ExifOrientationMode.Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using SixLabors.ImageSharp;
|
||||
using Umbraco.Cms.Core.Media;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Media
|
||||
{
|
||||
/// <summary>
|
||||
/// Exposes a method that generates an image URL based on the specified options that can be processed by ImageSharp.
|
||||
/// </summary>
|
||||
/// <seealso cref="Umbraco.Cms.Core.Media.IImageUrlGenerator" />
|
||||
public class ImageSharpImageUrlGenerator : IImageUrlGenerator
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<string> SupportedImageFileTypes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ImageSharpImageUrlGenerator" /> class.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The ImageSharp configuration.</param>
|
||||
public ImageSharpImageUrlGenerator(Configuration configuration)
|
||||
: this(configuration.ImageFormats.SelectMany(f => f.FileExtensions).ToArray())
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ImageSharpImageUrlGenerator" /> class.
|
||||
/// </summary>
|
||||
/// <param name="supportedImageFileTypes">The supported image file types/extensions.</param>
|
||||
/// <remarks>
|
||||
/// This constructor is only used for testing.
|
||||
/// </remarks>
|
||||
internal ImageSharpImageUrlGenerator(IEnumerable<string> supportedImageFileTypes) => SupportedImageFileTypes = supportedImageFileTypes;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string? GetImageUrl(ImageUrlGenerationOptions options)
|
||||
{
|
||||
if (options == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var imageUrl = new StringBuilder(options.ImageUrl);
|
||||
|
||||
bool queryStringHasStarted = false;
|
||||
void AppendQueryString(string value)
|
||||
{
|
||||
imageUrl.Append(queryStringHasStarted ? '&' : '?');
|
||||
queryStringHasStarted = true;
|
||||
|
||||
imageUrl.Append(value);
|
||||
}
|
||||
void AddQueryString(string key, params IConvertible[] values)
|
||||
=> AppendQueryString(key + '=' + string.Join(",", values.Select(x => x.ToString(CultureInfo.InvariantCulture))));
|
||||
|
||||
if (options.Crop != null)
|
||||
{
|
||||
AddQueryString("cc", options.Crop.Left, options.Crop.Top, options.Crop.Right, options.Crop.Bottom);
|
||||
}
|
||||
|
||||
if (options.FocalPoint != null)
|
||||
{
|
||||
AddQueryString("rxy", options.FocalPoint.Left, options.FocalPoint.Top);
|
||||
}
|
||||
|
||||
if (options.ImageCropMode.HasValue)
|
||||
{
|
||||
AddQueryString("rmode", options.ImageCropMode.Value.ToString().ToLowerInvariant());
|
||||
}
|
||||
|
||||
if (options.ImageCropAnchor.HasValue)
|
||||
{
|
||||
AddQueryString("ranchor", options.ImageCropAnchor.Value.ToString().ToLowerInvariant());
|
||||
}
|
||||
|
||||
if (options.Width.HasValue)
|
||||
{
|
||||
AddQueryString("width", options.Width.Value);
|
||||
}
|
||||
|
||||
if (options.Height.HasValue)
|
||||
{
|
||||
AddQueryString("height", options.Height.Value);
|
||||
}
|
||||
|
||||
if (options.Quality.HasValue)
|
||||
{
|
||||
AddQueryString("quality", options.Quality.Value);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(options.FurtherOptions) == false)
|
||||
{
|
||||
AppendQueryString(options.FurtherOptions.TrimStart('?', '&'));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(options.CacheBusterValue) == false)
|
||||
{
|
||||
AddQueryString("rnd", options.CacheBusterValue);
|
||||
}
|
||||
|
||||
return imageUrl.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,7 @@
|
||||
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Map" Version="1.0.2" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.1" />
|
||||
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" />
|
||||
<PackageReference Include="System.Text.Encodings.Web" Version="6.0.0" /> <!-- Explicit updated this nested dependency due to this https://github.com/dotnet/announcements/issues/178-->
|
||||
<PackageReference Include="System.Threading.Tasks.Dataflow" Version="6.0.0" />
|
||||
|
||||
Reference in New Issue
Block a user