diff --git a/src/Umbraco.Core/Media/ExifImageDimensionExtractor.cs b/src/Umbraco.Core/Media/ExifImageDimensionExtractor.cs deleted file mode 100644 index 8987b60fee..0000000000 --- a/src/Umbraco.Core/Media/ExifImageDimensionExtractor.cs +++ /dev/null @@ -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; - } - } -} diff --git a/src/Umbraco.Core/Media/IImageDimensionExtractor.cs b/src/Umbraco.Core/Media/IImageDimensionExtractor.cs index c31260a9ce..abbe8806b3 100644 --- a/src/Umbraco.Core/Media/IImageDimensionExtractor.cs +++ b/src/Umbraco.Core/Media/IImageDimensionExtractor.cs @@ -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); } } diff --git a/src/Umbraco.Core/Media/ImageSize.cs b/src/Umbraco.Core/Media/ImageSize.cs deleted file mode 100644 index 9acef58836..0000000000 --- a/src/Umbraco.Core/Media/ImageSize.cs +++ /dev/null @@ -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; - } - } -} diff --git a/src/Umbraco.Core/Media/ImageUrlGeneratorExtensions.cs b/src/Umbraco.Core/Media/ImageUrlGeneratorExtensions.cs index 5b7be5ef0e..9cdc6869f4 100644 --- a/src/Umbraco.Core/Media/ImageUrlGeneratorExtensions.cs +++ b/src/Umbraco.Core/Media/ImageUrlGeneratorExtensions.cs @@ -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 /// /// Gets a value indicating whether the file extension corresponds to a supported image. /// - /// The image URL generator implementation that provides detail on which image extension sare supported. + /// The image URL generator implementation that provides detail on which image extensions are supported. /// The file extension. - /// A value indicating whether the file extension corresponds to an image. + /// + /// A value indicating whether the file extension corresponds to an image. + /// + /// imageUrlGenerator 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)); } } } diff --git a/src/Umbraco.Core/Media/UploadAutoFillProperties.cs b/src/Umbraco.Core/Media/UploadAutoFillProperties.cs index 10a372ce9f..83357f8929 100644 --- a/src/Umbraco.Core/Media/UploadAutoFillProperties.cs +++ b/src/Umbraco.Core/Media/UploadAutoFillProperties.cs @@ -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)); diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs index c7f317a4ad..7268d7c4db 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs @@ -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(); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); diff --git a/src/Umbraco.Infrastructure/Media/ImageDimensionExtractor.cs b/src/Umbraco.Infrastructure/Media/ImageDimensionExtractor.cs deleted file mode 100644 index 380704c26c..0000000000 --- a/src/Umbraco.Infrastructure/Media/ImageDimensionExtractor.cs +++ /dev/null @@ -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 - { - /// - /// The ImageSharp configuration. - /// - private readonly Configuration _configuration; - - /// - /// Initializes a new instance of the class. - /// - /// The ImageSharp configuration. - public ImageDimensionExtractor(Configuration configuration) => _configuration = configuration; - - /// - /// Gets the dimensions of an image. - /// - /// A stream containing the image bytes. - /// The dimension of the image. - /// 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. - 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); - } - } -} diff --git a/src/Umbraco.Infrastructure/Media/ImageSharpDimensionExtractor.cs b/src/Umbraco.Infrastructure/Media/ImageSharpDimensionExtractor.cs new file mode 100644 index 0000000000..227d9a653c --- /dev/null +++ b/src/Umbraco.Infrastructure/Media/ImageSharpDimensionExtractor.cs @@ -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; + + /// + /// Initializes a new instance of the class. + /// + /// The configuration. + public ImageSharpDimensionExtractor(Configuration configuration) + => _configuration = configuration; + + /// + /// Gets the dimensions of an image. + /// + /// A stream containing the image bytes. + /// + /// The dimension of the image. + /// + 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; + } + } +}