Moved media files and introduced IImageDimensionExtractor and to avoid System.drawing in core

This commit is contained in:
Bjarke Berg
2020-12-04 15:04:29 +01:00
parent 21e3cf0887
commit eb03145fa6
61 changed files with 163 additions and 87 deletions

View File

@@ -3,10 +3,9 @@ using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Umbraco.Core.Security;
using Umbraco.Net;
using Umbraco.Core.Services;
using Umbraco.Net;
using Umbraco.Web.Install.Models;
using Umbraco.Web.Security;
namespace Umbraco.Web.Install.InstallSteps
{

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Umbraco.Core.Serialization;
namespace Umbraco.Web.Media.EmbedProviders
{
@@ -10,7 +11,7 @@ namespace Umbraco.Web.Media.EmbedProviders
{
@"dailymotion.com/video/.*"
};
public override Dictionary<string, string> RequestParams => new Dictionary<string, string>()
{
//ApiUrl/?format=xml
@@ -24,5 +25,9 @@ namespace Umbraco.Web.Media.EmbedProviders
return GetXmlProperty(xmlDocument, "/oembed/html");
}
public DailyMotion(IJsonSerializer jsonSerializer) : base(jsonSerializer)
{
}
}
}

View File

@@ -1,16 +1,23 @@
using Newtonsoft.Json;
using System;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Xml;
using Umbraco.Core.Media;
using Umbraco.Core.Serialization;
namespace Umbraco.Web.Media.EmbedProviders
{
public abstract class EmbedProviderBase : IEmbedProvider
{
private readonly IJsonSerializer _jsonSerializer;
protected EmbedProviderBase(IJsonSerializer jsonSerializer)
{
_jsonSerializer = jsonSerializer;
}
private static HttpClient _httpClient;
public abstract string ApiEndpoint { get; }
@@ -58,7 +65,7 @@ namespace Umbraco.Web.Media.EmbedProviders
public virtual T GetJsonResponse<T>(string url) where T : class
{
var response = DownloadResponse(url);
return JsonConvert.DeserializeObject<T>(response);
return _jsonSerializer.Deserialize<T>(response);
}
public virtual XmlDocument GetXmlResponse(string url)

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Net;
using Umbraco.Core.Serialization;
namespace Umbraco.Web.Media.EmbedProviders
{
@@ -27,5 +28,9 @@ namespace Umbraco.Web.Media.EmbedProviders
return string.Format("<img src=\"{0}\" width=\"{1}\" height=\"{2}\" alt=\"{3}\" />", imageUrl, imageWidth, imageHeight, WebUtility.HtmlEncode(imageTitle));
}
public Flickr(IJsonSerializer jsonSerializer) : base(jsonSerializer)
{
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Umbraco.Core.Serialization;
namespace Umbraco.Web.Media.EmbedProviders
{
@@ -23,5 +24,9 @@ namespace Umbraco.Web.Media.EmbedProviders
return oembed.GetHtml();
}
public GettyImages(IJsonSerializer jsonSerializer) : base(jsonSerializer)
{
}
}
}

View File

@@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Generic;
using Umbraco.Core.Serialization;
namespace Umbraco.Web.Media.EmbedProviders
{
@@ -28,5 +25,9 @@ namespace Umbraco.Web.Media.EmbedProviders
return oembed.GetHtml();
}
public Giphy(IJsonSerializer jsonSerializer) : base(jsonSerializer)
{
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Umbraco.Core.Serialization;
namespace Umbraco.Web.Media.EmbedProviders
{
@@ -10,7 +11,7 @@ namespace Umbraco.Web.Media.EmbedProviders
{
@"hulu.com/watch/.*"
};
public override Dictionary<string, string> RequestParams => new Dictionary<string, string>();
public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0)
@@ -20,5 +21,9 @@ namespace Umbraco.Web.Media.EmbedProviders
return oembed.GetHtml();
}
public Hulu(IJsonSerializer jsonSerializer) : base(jsonSerializer)
{
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Umbraco.Core.Serialization;
namespace Umbraco.Web.Media.EmbedProviders
{
@@ -10,7 +11,7 @@ namespace Umbraco.Web.Media.EmbedProviders
{
@"issuu.com/.*/docs/.*"
};
public override Dictionary<string, string> RequestParams => new Dictionary<string, string>()
{
//ApiUrl/?format=xml
@@ -24,5 +25,9 @@ namespace Umbraco.Web.Media.EmbedProviders
return GetXmlProperty(xmlDocument, "/oembed/html");
}
public Issuu(IJsonSerializer jsonSerializer) : base(jsonSerializer)
{
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Umbraco.Core.Serialization;
namespace Umbraco.Web.Media.EmbedProviders
{
@@ -20,5 +21,9 @@ namespace Umbraco.Web.Media.EmbedProviders
return oembed.GetHtml();
}
public Kickstarter(IJsonSerializer jsonSerializer) : base(jsonSerializer)
{
}
}
}

View File

@@ -1,11 +1,12 @@
using System.Net;
using Newtonsoft.Json;
using System.Runtime.Serialization;
namespace Umbraco.Web.Media.EmbedProviders
{
/// <summary>
/// Wrapper class for OEmbed response
/// </summary>
[DataContract]
public class OEmbedResponse
{
public string Type { get; set; }
@@ -14,25 +15,25 @@ namespace Umbraco.Web.Media.EmbedProviders
public string Title { get; set; }
[JsonProperty("author_name")]
[DataMember(Name ="author_name")]
public string AuthorName { get; set; }
[JsonProperty("author_url")]
[DataMember(Name ="author_url")]
public string AuthorUrl { get; set; }
[JsonProperty("provider_name")]
[DataMember(Name ="provider_name")]
public string ProviderName { get; set; }
[JsonProperty("provider_url")]
[DataMember(Name ="provider_url")]
public string ProviderUrl { get; set; }
[JsonProperty("thumbnail_url")]
[DataMember(Name ="thumbnail_url")]
public string ThumbnailUrl { get; set; }
[JsonProperty("thumbnail_height")]
[DataMember(Name ="thumbnail_height")]
public double? ThumbnailHeight { get; set; }
[JsonProperty("thumbnail_width")]
[DataMember(Name ="thumbnail_width")]
public double? ThumbnailWidth { get; set; }
public string Html { get; set; }

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Umbraco.Core.Serialization;
namespace Umbraco.Web.Media.EmbedProviders
{
@@ -20,5 +21,9 @@ namespace Umbraco.Web.Media.EmbedProviders
return GetXmlProperty(xmlDocument, "/oembed/html");
}
public Slideshare(IJsonSerializer jsonSerializer) : base(jsonSerializer)
{
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Umbraco.Core.Serialization;
namespace Umbraco.Web.Media.EmbedProviders
{
@@ -10,7 +11,7 @@ namespace Umbraco.Web.Media.EmbedProviders
{
@"soundcloud.com\/*"
};
public override Dictionary<string, string> RequestParams => new Dictionary<string, string>();
public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0)
@@ -20,5 +21,9 @@ namespace Umbraco.Web.Media.EmbedProviders
return GetXmlProperty(xmlDocument, "/oembed/html");
}
public Soundcloud(IJsonSerializer jsonSerializer) : base(jsonSerializer)
{
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Umbraco.Core.Serialization;
namespace Umbraco.Web.Media.EmbedProviders
{
@@ -10,7 +11,7 @@ namespace Umbraco.Web.Media.EmbedProviders
{
@"ted.com\/talks\/*"
};
public override Dictionary<string, string> RequestParams => new Dictionary<string, string>();
public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0)
@@ -20,5 +21,9 @@ namespace Umbraco.Web.Media.EmbedProviders
return GetXmlProperty(xmlDocument, "/oembed/html");
}
public Ted(IJsonSerializer jsonSerializer) : base(jsonSerializer)
{
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Umbraco.Core.Serialization;
namespace Umbraco.Web.Media.EmbedProviders
{
@@ -20,5 +21,9 @@ namespace Umbraco.Web.Media.EmbedProviders
return oembed.GetHtml();
}
public Twitter(IJsonSerializer jsonSerializer) : base(jsonSerializer)
{
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Umbraco.Core.Serialization;
namespace Umbraco.Web.Media.EmbedProviders
{
@@ -10,7 +11,7 @@ namespace Umbraco.Web.Media.EmbedProviders
{
@"vimeo\.com/"
};
public override Dictionary<string, string> RequestParams => new Dictionary<string, string>();
public override string GetMarkup(string url, int maxWidth = 0, int maxHeight = 0)
@@ -20,5 +21,9 @@ namespace Umbraco.Web.Media.EmbedProviders
return GetXmlProperty(xmlDocument, "/oembed/html");
}
public Vimeo(IJsonSerializer jsonSerializer) : base(jsonSerializer)
{
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Umbraco.Core.Serialization;
namespace Umbraco.Web.Media.EmbedProviders
{
@@ -11,7 +12,7 @@ namespace Umbraco.Web.Media.EmbedProviders
@"youtu.be/.*",
@"youtube.com/watch.*"
};
public override Dictionary<string, string> RequestParams => new Dictionary<string, string>()
{
//ApiUrl/?format=json
@@ -25,5 +26,9 @@ namespace Umbraco.Web.Media.EmbedProviders
return oembed.GetHtml();
}
public YouTube(IJsonSerializer jsonSerializer) : base(jsonSerializer)
{
}
}
}

View File

@@ -1,5 +1,4 @@
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Text;
using Umbraco.Web.Media.TypeDetector;
@@ -52,11 +51,6 @@ namespace Umbraco.Web.Media.Exif
#endregion
#region Instance Methods
/// <summary>
/// Converts the <see cref="ImageFile"/> to a <see cref="System.Drawing.Image"/>.
/// </summary>
/// <returns>Returns a <see cref="System.Drawing.Image"/> containing image data.</returns>
public abstract Image ToImage ();
/// <summary>
/// Saves the <see cref="ImageFile"/> to the specified file.

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
@@ -260,15 +259,6 @@ namespace Umbraco.Web.Media.Exif
Save(stream, true);
}
/// <summary>
/// Returns a System.Drawing.Image created with image data.
/// </summary>
public override Image ToImage()
{
MemoryStream stream = new MemoryStream();
Save(stream);
return Image.FromStream(stream);
}
#endregion
#region Private Helper Methods

View File

@@ -1,6 +1,4 @@
using System;
using System.Drawing;
using System.IO;
using System.IO;
using System.Linq;
using System.Xml.Linq;
@@ -29,9 +27,5 @@ namespace Umbraco.Web.Media.Exif
{
}
public override Image ToImage()
{
throw new NotImplementedException();
}
}
}

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
namespace Umbraco.Web.Media.Exif
@@ -162,16 +161,6 @@ namespace Umbraco.Web.Media.Exif
}
}
/// <summary>
/// Converts the <see cref="ImageFile"/> to a <see cref="System.Drawing.Image"/>.
/// </summary>
/// <returns>Returns a <see cref="System.Drawing.Image"/> containing image data.</returns>
public override Image ToImage()
{
MemoryStream stream = new MemoryStream();
Save(stream);
return Image.FromStream(stream);
}
#endregion
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.IO;
using Umbraco.Web.Media.Exif;
namespace Umbraco.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;
}
}
}

View File

@@ -7,7 +7,6 @@ using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Umbraco.Core;
using Umbraco.Core.BackOffice;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Migrations.Install;
using Umbraco.Core.Services;
@@ -25,7 +24,7 @@ namespace Umbraco.Web.Install.InstallSteps
/// display a simple continue installation view.
/// </remarks>
[InstallSetupStep(InstallationType.NewInstall, "User", 20, "")]
internal class NewInstallStep : InstallSetupStep<UserModel>
public class NewInstallStep : InstallSetupStep<UserModel>
{
private readonly IUserService _userService;
private readonly DatabaseBuilder _databaseBuilder;

View File

@@ -0,0 +1,9 @@
using System.IO;
namespace Umbraco.Web.Media
{
public interface IImageDimensionExtractor
{
public ImageSize GetDimensions(Stream stream);
}
}

View File

@@ -2,11 +2,11 @@
using System.Drawing;
using System.IO;
using Umbraco.Core;
using Umbraco.Web.Media.Exif;
using Umbraco.Core.Media;
namespace Umbraco.Web.Media
{
public static class ImageHelper
internal class ImageDimensionExtractor : IImageDimensionExtractor
{
/// <summary>
/// Gets the dimensions of an image.
@@ -16,24 +16,14 @@ namespace Umbraco.Web.Media
/// <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 static Size GetDimensions(Stream stream)
public ImageSize GetDimensions(Stream stream)
{
//Try to load with exif
try
{
var jpgInfo = ImageFile.FromStream(stream);
if (jpgInfo != null
&& jpgInfo.Format != ImageFileFormat.Unknown
&& jpgInfo.Properties.ContainsKey(ExifTag.PixelYDimension)
&& jpgInfo.Properties.ContainsKey(ExifTag.PixelXDimension))
if (ExifImageDimensionExtractor.TryGetDimensions(stream, out var width, out var height))
{
var height = Convert.ToInt32(jpgInfo.Properties[ExifTag.PixelYDimension].Value);
var width = Convert.ToInt32(jpgInfo.Properties[ExifTag.PixelXDimension].Value);
if (height > 0 && width > 0)
{
return new Size(width, height);
}
return new ImageSize(width, height);
}
}
catch
@@ -48,7 +38,7 @@ namespace Umbraco.Web.Media
{
var fileWidth = image.Width;
var fileHeight = image.Height;
return new Size(fileWidth, fileHeight);
return new ImageSize(fileWidth, fileHeight);
}
}
catch (Exception)
@@ -56,7 +46,7 @@ namespace Umbraco.Web.Media
//We will just swallow, just means we can't read via GDI, we don't want to log an error either
}
return new Size(Constants.Conventions.Media.DefaultSize, Constants.Conventions.Media.DefaultSize);
return new ImageSize(Constants.Conventions.Media.DefaultSize, Constants.Conventions.Media.DefaultSize);
}
}
}

View File

@@ -0,0 +1,15 @@
namespace Umbraco.Web.Media
{
public struct ImageSize
{
public int Width { get; }
public int Height { get; }
public ImageSize(int width, int height)
{
Width = width;
Height = height;
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Drawing;
using System.IO;
using Microsoft.Extensions.Logging;
using Umbraco.Core;
@@ -18,15 +17,18 @@ namespace Umbraco.Web.Media
private readonly IMediaFileSystem _mediaFileSystem;
private readonly ILogger<UploadAutoFillProperties> _logger;
private readonly IImageUrlGenerator _imageUrlGenerator;
private readonly IImageDimensionExtractor _imageDimensionExtractor;
public UploadAutoFillProperties(
IMediaFileSystem mediaFileSystem,
ILogger<UploadAutoFillProperties> logger,
IImageUrlGenerator imageUrlGenerator)
IImageUrlGenerator imageUrlGenerator,
IImageDimensionExtractor imageDimensionExtractor)
{
_mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_imageUrlGenerator = imageUrlGenerator ?? throw new ArgumentNullException(nameof(imageUrlGenerator));
_imageDimensionExtractor = imageDimensionExtractor ?? throw new ArgumentNullException(nameof(imageDimensionExtractor));
}
/// <summary>
@@ -71,7 +73,7 @@ namespace Umbraco.Web.Media
using (var filestream = _mediaFileSystem.OpenFile(filepath))
{
var extension = (Path.GetExtension(filepath) ?? "").TrimStart('.');
var size = _imageUrlGenerator.IsSupportedImageFormat(extension) ? (Size?)ImageHelper.GetDimensions(filestream) : null;
var size = _imageUrlGenerator.IsSupportedImageFormat(extension) ? (ImageSize?)_imageDimensionExtractor.GetDimensions(filestream) : null;
SetProperties(content, autoFillConfig, size, filestream.Length, extension, culture, segment);
}
}
@@ -105,12 +107,12 @@ namespace Umbraco.Web.Media
else
{
var extension = (Path.GetExtension(filepath) ?? "").TrimStart('.');
var size = _imageUrlGenerator.IsSupportedImageFormat(extension) ? (Size?)ImageHelper.GetDimensions(filestream) : null;
var size = _imageUrlGenerator.IsSupportedImageFormat(extension) ? (ImageSize?)_imageDimensionExtractor.GetDimensions(filestream) : 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)
private static void SetProperties(IContentBase content, ImagingAutoFillUploadField autoFillConfig, ImageSize? 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));

View File

@@ -1,6 +1,7 @@
using System;
using Examine;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
@@ -9,6 +10,7 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.Grid;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Dashboards;
using Umbraco.Core.DependencyInjection;
using Umbraco.Core.Dictionary;
using Umbraco.Core.Events;
using Umbraco.Core.Hosting;
@@ -25,6 +27,7 @@ using Umbraco.Core.PropertyEditors;
using Umbraco.Core.PropertyEditors.Validators;
using Umbraco.Core.PropertyEditors.ValueConverters;
using Umbraco.Core.Scoping;
using Umbraco.Core.Security;
using Umbraco.Core.Serialization;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Implement;
@@ -56,11 +59,7 @@ using Umbraco.Web.Sections;
using Umbraco.Web.Services;
using Umbraco.Web.Templates;
using Umbraco.Web.Trees;
using IntegerValidator = Umbraco.Core.PropertyEditors.Validators.IntegerValidator;
using TextStringValueConverter = Umbraco.Core.PropertyEditors.ValueConverters.TextStringValueConverter;
using Microsoft.Extensions.Logging;
using Umbraco.Core.DependencyInjection;
using Umbraco.Core.Security;
namespace Umbraco.Core.Runtime
{
@@ -379,6 +378,7 @@ namespace Umbraco.Core.Runtime
builder.Services.AddUnique<UserEditorAuthorizationHelper>();
builder.Services.AddUnique<ContentPermissions>();
builder.Services.AddUnique<MediaPermissions>();
builder.Services.AddUnique<IImageDimensionExtractor, ImageDimensionExtractor>();
}
}
}