Merge pull request #10964 from umbraco/v9/bugfix/imagesize-cleanup
Use ImageSharps Image.Identify for dimension extraction
This commit is contained in:
@@ -1,26 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Umbraco.Cms.Core.Media.Exif;
|
||||
|
||||
namespace Umbraco.Cms.Core.Media
|
||||
{
|
||||
public static class ExifImageDimensionExtractor
|
||||
{
|
||||
public static bool TryGetDimensions(Stream stream, out int width, out int height)
|
||||
{
|
||||
var jpgInfo = ImageFile.FromStream(stream);
|
||||
height = -1;
|
||||
width = -1;
|
||||
if (jpgInfo != null
|
||||
&& jpgInfo.Format != ImageFileFormat.Unknown
|
||||
&& jpgInfo.Properties.ContainsKey(ExifTag.PixelYDimension)
|
||||
&& jpgInfo.Properties.ContainsKey(ExifTag.PixelXDimension))
|
||||
{
|
||||
height = Convert.ToInt32(jpgInfo.Properties[ExifTag.PixelYDimension].Value);
|
||||
width = Convert.ToInt32(jpgInfo.Properties[ExifTag.PixelXDimension].Value);
|
||||
}
|
||||
|
||||
return height > 0 && width > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
using System.IO;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
|
||||
namespace Umbraco.Cms.Core.Media
|
||||
{
|
||||
public interface IImageDimensionExtractor
|
||||
{
|
||||
public ImageSize GetDimensions(Stream stream);
|
||||
public Size? GetDimensions(Stream stream);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
namespace Umbraco.Cms.Core.Media
|
||||
{
|
||||
public struct ImageSize
|
||||
{
|
||||
public int Width { get; }
|
||||
public int Height { get; }
|
||||
|
||||
|
||||
public ImageSize(int width, int height)
|
||||
{
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Media;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
@@ -8,15 +9,21 @@ namespace Umbraco.Extensions
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the file extension corresponds to a supported image.
|
||||
/// </summary>
|
||||
/// <param name="imageUrlGenerator">The image URL generator implementation that provides detail on which image extension sare supported.</param>
|
||||
/// <param name="imageUrlGenerator">The image URL generator implementation that provides detail on which image extensions are supported.</param>
|
||||
/// <param name="extension">The file extension.</param>
|
||||
/// <returns>A value indicating whether the file extension corresponds to an image.</returns>
|
||||
/// <returns>
|
||||
/// A value indicating whether the file extension corresponds to an image.
|
||||
/// </returns>
|
||||
/// <exception cref="System.ArgumentNullException">imageUrlGenerator</exception>
|
||||
public static bool IsSupportedImageFormat(this IImageUrlGenerator imageUrlGenerator, string extension)
|
||||
{
|
||||
if (imageUrlGenerator == null) throw new ArgumentNullException(nameof(imageUrlGenerator));
|
||||
if (extension == null) return false;
|
||||
extension = extension.TrimStart('.');
|
||||
return imageUrlGenerator.SupportedImageFileTypes.InvariantContains(extension);
|
||||
if (imageUrlGenerator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(imageUrlGenerator));
|
||||
}
|
||||
|
||||
return string.IsNullOrWhiteSpace(extension) == false &&
|
||||
imageUrlGenerator.SupportedImageFileTypes.InvariantContains(extension.TrimStart(Constants.CharArrays.Period));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
@@ -74,9 +75,7 @@ namespace Umbraco.Cms.Core.Media
|
||||
{
|
||||
using (var filestream = _mediaFileManager.FileSystem.OpenFile(filepath))
|
||||
{
|
||||
var extension = (Path.GetExtension(filepath) ?? "").TrimStart(Constants.CharArrays.Period);
|
||||
var size = _imageUrlGenerator.IsSupportedImageFormat(extension) ? (ImageSize?)_imageDimensionExtractor.GetDimensions(filestream) : null;
|
||||
SetProperties(content, autoFillConfig, size, filestream.Length, extension, culture, segment);
|
||||
SetProperties(content, autoFillConfig, filepath, filestream, culture, segment);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -109,13 +108,22 @@ namespace Umbraco.Cms.Core.Media
|
||||
}
|
||||
else
|
||||
{
|
||||
var extension = (Path.GetExtension(filepath) ?? "").TrimStart(Constants.CharArrays.Period);
|
||||
var size = _imageUrlGenerator.IsSupportedImageFormat(extension) ? (ImageSize?)_imageDimensionExtractor.GetDimensions(filestream) : null;
|
||||
SetProperties(content, autoFillConfig, size, filestream.Length, extension, culture, segment);
|
||||
SetProperties(content, autoFillConfig, filepath, filestream, culture, segment);
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetProperties(IContentBase content, ImagingAutoFillUploadField autoFillConfig, ImageSize? size, long length, string extension, string culture, string segment)
|
||||
private void SetProperties(IContentBase content, ImagingAutoFillUploadField autoFillConfig, string filepath, Stream filestream, string culture, string segment)
|
||||
{
|
||||
var extension = (Path.GetExtension(filepath) ?? string.Empty).TrimStart(Constants.CharArrays.Period);
|
||||
|
||||
var size = _imageUrlGenerator.IsSupportedImageFormat(extension)
|
||||
? _imageDimensionExtractor.GetDimensions(filestream) ?? (Size?)new Size(Constants.Conventions.Media.DefaultSize, Constants.Conventions.Media.DefaultSize)
|
||||
: null;
|
||||
|
||||
SetProperties(content, autoFillConfig, size, filestream.Length, extension, culture, segment);
|
||||
}
|
||||
|
||||
private static void SetProperties(IContentBase content, ImagingAutoFillUploadField autoFillConfig, Size? size, long length, string extension, string culture, string segment)
|
||||
{
|
||||
if (content == null) throw new ArgumentNullException(nameof(content));
|
||||
if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig));
|
||||
|
||||
@@ -189,7 +189,7 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
|
||||
// Add default ImageSharp configuration and service implementations
|
||||
builder.Services.AddSingleton(SixLabors.ImageSharp.Configuration.Default);
|
||||
builder.Services.AddSingleton<IImageDimensionExtractor, ImageDimensionExtractor>();
|
||||
builder.Services.AddSingleton<IImageDimensionExtractor, ImageSharpDimensionExtractor>();
|
||||
builder.Services.AddSingleton<IImageUrlGenerator, ImageSharpImageUrlGenerator>();
|
||||
|
||||
builder.Services.AddSingleton<PackageDataInstallation>();
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SixLabors.ImageSharp;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Media;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Media
|
||||
{
|
||||
internal class ImageDimensionExtractor : IImageDimensionExtractor
|
||||
{
|
||||
/// <summary>
|
||||
/// The ImageSharp configuration.
|
||||
/// </summary>
|
||||
private readonly Configuration _configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ImageDimensionExtractor" /> class.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The ImageSharp configuration.</param>
|
||||
public ImageDimensionExtractor(Configuration configuration) => _configuration = configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dimensions of an image.
|
||||
/// </summary>
|
||||
/// <param name="stream">A stream containing the image bytes.</param>
|
||||
/// <returns>The dimension of the image.</returns>
|
||||
/// <remarks>First try with EXIF as it is faster and does not load the entire image
|
||||
/// in memory. Fallback to GDI which means loading the image in memory and thus
|
||||
/// use potentially large amounts of memory.</remarks>
|
||||
public ImageSize GetDimensions(Stream stream)
|
||||
{
|
||||
// Try to load with exif
|
||||
try
|
||||
{
|
||||
if (ExifImageDimensionExtractor.TryGetDimensions(stream, out var width, out var height))
|
||||
{
|
||||
return new ImageSize(width, height);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// We will just swallow, just means we can't read exif data, we don't want to log an error either
|
||||
}
|
||||
|
||||
// we have no choice but to try to read in via GDI
|
||||
try
|
||||
{
|
||||
if (stream.CanRead && stream.CanSeek)
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
using (var image = Image.Load(_configuration, stream))
|
||||
{
|
||||
var fileWidth = image.Width;
|
||||
var fileHeight = image.Height;
|
||||
return new ImageSize(fileWidth, fileHeight);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// We will just swallow, just means we can't read via GDI, we don't want to log an error either
|
||||
}
|
||||
|
||||
return new ImageSize(Constants.Conventions.Media.DefaultSize, Constants.Conventions.Media.DefaultSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System.IO;
|
||||
using SixLabors.ImageSharp;
|
||||
using Umbraco.Cms.Core.Media;
|
||||
using Size = System.Drawing.Size;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Media
|
||||
{
|
||||
internal class ImageSharpDimensionExtractor : IImageDimensionExtractor
|
||||
{
|
||||
private readonly Configuration _configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ImageSharpDimensionExtractor" /> class.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
public ImageSharpDimensionExtractor(Configuration configuration)
|
||||
=> _configuration = configuration;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dimensions of an image.
|
||||
/// </summary>
|
||||
/// <param name="stream">A stream containing the image bytes.</param>
|
||||
/// <returns>
|
||||
/// The dimension of the image.
|
||||
/// </returns>
|
||||
public Size? GetDimensions(Stream stream)
|
||||
{
|
||||
Size? size = null;
|
||||
|
||||
IImageInfo imageInfo = Image.Identify(_configuration, stream);
|
||||
if (imageInfo != null)
|
||||
{
|
||||
size = new Size(imageInfo.Width, imageInfo.Height);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user