diff --git a/src/Umbraco.Abstractions/Models/IImageUrlGenerator.cs b/src/Umbraco.Abstractions/Models/IImageUrlGenerator.cs
new file mode 100644
index 0000000000..0dc2933fd9
--- /dev/null
+++ b/src/Umbraco.Abstractions/Models/IImageUrlGenerator.cs
@@ -0,0 +1,7 @@
+namespace Umbraco.Core.Models
+{
+ public interface IImageUrlGenerator
+ {
+ string GetImageUrl(ImageUrlGenerationOptions options);
+ }
+}
diff --git a/src/Umbraco.Abstractions/Models/ImageUrlGenerationOptions.cs b/src/Umbraco.Abstractions/Models/ImageUrlGenerationOptions.cs
new file mode 100644
index 0000000000..f87657c33d
--- /dev/null
+++ b/src/Umbraco.Abstractions/Models/ImageUrlGenerationOptions.cs
@@ -0,0 +1,66 @@
+namespace Umbraco.Core.Models
+{
+ ///
+ /// These are options that are passed to the IImageUrlGenerator implementation to determine
+ /// the propery URL that is needed
+ ///
+ public class ImageUrlGenerationOptions
+ {
+ public ImageUrlGenerationOptions (string imageUrl)
+ {
+ ImageUrl = imageUrl;
+ }
+
+ public string ImageUrl { get; }
+ public int? Width { get; set; }
+ public int? Height { get; set; }
+ public decimal? WidthRatio { get; set; }
+ public decimal? HeightRatio { get; set; }
+ public int? Quality { get; set; }
+ public string ImageCropMode { get; set; }
+ public string ImageCropAnchor { get; set; }
+ public bool DefaultCrop { get; set; }
+ public FocalPointPosition FocalPoint { get; set; }
+ public CropCoordinates Crop { get; set; }
+ public string CacheBusterValue { get; set; }
+ public string FurtherOptions { get; set; }
+ public bool UpScale { get; set; } = true;
+ public string AnimationProcessMode { get; set; }
+
+ ///
+ /// The focal point position, in whatever units the registered IImageUrlGenerator uses,
+ /// typically a percentage of the total image from 0.0 to 1.0.
+ ///
+ public class FocalPointPosition
+ {
+ public FocalPointPosition (decimal top, decimal left)
+ {
+ Left = left;
+ Top = top;
+ }
+
+ public decimal Left { get; }
+ public decimal Top { get; }
+ }
+
+ ///
+ /// The bounds of the crop within the original image, in whatever units the registered
+ /// IImageUrlGenerator uses, typically a percentage between 0 and 100.
+ ///
+ public class CropCoordinates
+ {
+ public CropCoordinates (decimal x1, decimal y1, decimal x2, decimal y2)
+ {
+ X1 = x1;
+ Y1 = y1;
+ X2 = x2;
+ Y2 = y2;
+ }
+
+ public decimal X1 { get; }
+ public decimal Y1 { get; }
+ public decimal X2 { get; }
+ public decimal Y2 { get; }
+ }
+ }
+}
diff --git a/src/Umbraco.Infrastructure/Models/UserExtensions.cs b/src/Umbraco.Infrastructure/Models/UserExtensions.cs
index ebc5fab793..0c0e4fbc48 100644
--- a/src/Umbraco.Infrastructure/Models/UserExtensions.cs
+++ b/src/Umbraco.Infrastructure/Models/UserExtensions.cs
@@ -1,12 +1,9 @@
using System;
using System.Collections.Generic;
-using System.Globalization;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using Umbraco.Core.Cache;
-using Umbraco.Core.Configuration;
-using Umbraco.Core.Composing;
using Umbraco.Core.IO;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Models.Membership;
@@ -26,7 +23,7 @@ namespace Umbraco.Core.Models
///
/// A list of 5 different sized avatar URLs
///
- public static string[] GetUserAvatarUrls(this IUser user, IAppCache cache, IMediaFileSystem mediaFileSystem)
+ public static string[] GetUserAvatarUrls(this IUser user, IAppCache cache, IMediaFileSystem mediaFileSystem, IImageUrlGenerator imageUrlGenerator)
{
// If FIPS is required, never check the Gravatar service as it only supports MD5 hashing.
// Unfortunately, if the FIPS setting is enabled on Windows, using MD5 will throw an exception
@@ -80,11 +77,11 @@ namespace Umbraco.Core.Models
var avatarUrl = mediaFileSystem.GetUrl(user.Avatar);
return new[]
{
- avatarUrl + "?width=30&height=30&mode=crop",
- avatarUrl + "?width=60&height=60&mode=crop",
- avatarUrl + "?width=90&height=90&mode=crop",
- avatarUrl + "?width=150&height=150&mode=crop",
- avatarUrl + "?width=300&height=300&mode=crop"
+ imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl) { ImageCropMode = "crop", Width = 30, Height = 30 }),
+ imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl) { ImageCropMode = "crop", Width = 60, Height = 60 }),
+ imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl) { ImageCropMode = "crop", Width = 90, Height = 90 }),
+ imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl) { ImageCropMode = "crop", Width = 150, Height = 150 }),
+ imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(avatarUrl) { ImageCropMode = "crop", Width = 300, Height = 300 })
};
}
diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditRepository.cs
index 0788594e3a..4cb533e86f 100644
--- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditRepository.cs
+++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditRepository.cs
@@ -77,7 +77,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
public IEnumerable Get(AuditType type, IQuery query)
{
var sqlClause = GetBaseQuery(false)
- .Where(x => x.Header == type.ToString());
+ .Where("(logHeader=@0)", type.ToString());
+
var translator = new SqlTranslator(sqlClause, query);
var sql = translator.Translate();
diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValue.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValue.cs
index 89cd7b49c3..1367c04cdb 100644
--- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValue.cs
+++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValue.cs
@@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
-using System.Globalization;
using System.Linq;
using System.Runtime.Serialization;
-using System.Text;
using Newtonsoft.Json;
+using Umbraco.Core.Models;
using Umbraco.Core.Serialization;
using Umbraco.Core.Strings;
@@ -59,38 +58,28 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
: Crops.FirstOrDefault(x => x.Alias.InvariantEquals(alias));
}
- public void AppendCropBaseUrl(StringBuilder url, ImageCropperCrop crop, bool defaultCrop, bool preferFocalPoint)
+ public ImageUrlGenerationOptions GetCropBaseOptions(string url, ImageCropperCrop crop, bool defaultCrop, bool preferFocalPoint)
{
if (preferFocalPoint && HasFocalPoint()
|| crop != null && crop.Coordinates == null && HasFocalPoint()
|| defaultCrop && HasFocalPoint())
{
- url.Append("?center=");
- url.Append(FocalPoint.Top.ToString(CultureInfo.InvariantCulture));
- url.Append(",");
- url.Append(FocalPoint.Left.ToString(CultureInfo.InvariantCulture));
- url.Append("&mode=crop");
+ return new ImageUrlGenerationOptions(url) { FocalPoint = new ImageUrlGenerationOptions.FocalPointPosition(FocalPoint.Top, FocalPoint.Left) };
}
else if (crop != null && crop.Coordinates != null && preferFocalPoint == false)
{
- url.Append("?crop=");
- url.Append(crop.Coordinates.X1.ToString(CultureInfo.InvariantCulture)).Append(",");
- url.Append(crop.Coordinates.Y1.ToString(CultureInfo.InvariantCulture)).Append(",");
- url.Append(crop.Coordinates.X2.ToString(CultureInfo.InvariantCulture)).Append(",");
- url.Append(crop.Coordinates.Y2.ToString(CultureInfo.InvariantCulture));
- url.Append("&cropmode=percentage");
+ return new ImageUrlGenerationOptions(url) { Crop = new ImageUrlGenerationOptions.CropCoordinates(crop.Coordinates.X1, crop.Coordinates.Y1, crop.Coordinates.X2, crop.Coordinates.Y2) };
}
else
{
- url.Append("?anchor=center");
- url.Append("&mode=crop");
+ return new ImageUrlGenerationOptions(url) { DefaultCrop = true };
}
}
///
/// Gets the value image url for a specified crop.
///
- public string GetCropUrl(string alias, bool useCropDimensions = true, bool useFocalPoint = false, string cacheBusterValue = null)
+ public string GetCropUrl(string alias, IImageUrlGenerator imageUrlGenerator, bool useCropDimensions = true, bool useFocalPoint = false, string cacheBusterValue = null)
{
var crop = GetCrop(alias);
@@ -98,38 +87,31 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
if (crop == null && !string.IsNullOrWhiteSpace(alias))
return null;
- var url = new StringBuilder();
-
- AppendCropBaseUrl(url, crop, string.IsNullOrWhiteSpace(alias), useFocalPoint);
+ var options = GetCropBaseOptions(string.Empty, crop, string.IsNullOrWhiteSpace(alias), useFocalPoint);
if (crop != null && useCropDimensions)
{
- url.Append("&width=").Append(crop.Width);
- url.Append("&height=").Append(crop.Height);
+ options.Width = crop.Width;
+ options.Height = crop.Height;
}
- if (cacheBusterValue != null)
- url.Append("&rnd=").Append(cacheBusterValue);
+ options.CacheBusterValue = cacheBusterValue;
- return url.ToString();
+ return imageUrlGenerator.GetImageUrl(options);
}
///
/// Gets the value image url for a specific width and height.
///
- public string GetCropUrl(int width, int height, bool useFocalPoint = false, string cacheBusterValue = null)
+ public string GetCropUrl(int width, int height, IImageUrlGenerator imageUrlGenerator, bool useFocalPoint = false, string cacheBusterValue = null)
{
- var url = new StringBuilder();
+ var options = GetCropBaseOptions(string.Empty, null, true, useFocalPoint);
- AppendCropBaseUrl(url, null, true, useFocalPoint);
+ options.Width = width;
+ options.Height = height;
+ options.CacheBusterValue = cacheBusterValue;
- url.Append("&width=").Append(width);
- url.Append("&height=").Append(height);
-
- if (cacheBusterValue != null)
- url.Append("&rnd=").Append(cacheBusterValue);
-
- return url.ToString();
+ return imageUrlGenerator.GetImageUrl(options);
}
///
diff --git a/src/Umbraco.Infrastructure/Services/Implement/AuditService.cs b/src/Umbraco.Infrastructure/Services/Implement/AuditService.cs
index 5eb08f2dea..7d3be1d52b 100644
--- a/src/Umbraco.Infrastructure/Services/Implement/AuditService.cs
+++ b/src/Umbraco.Infrastructure/Services/Implement/AuditService.cs
@@ -142,7 +142,7 @@ namespace Umbraco.Core.Services.Implement
if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex));
if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize));
- if (userId < 0)
+ if (userId < Constants.Security.SuperUserId)
{
totalRecords = 0;
return Enumerable.Empty();
diff --git a/src/Umbraco.Tests/Models/ImageProcessorImageUrlGeneratorTest.cs b/src/Umbraco.Tests/Models/ImageProcessorImageUrlGeneratorTest.cs
new file mode 100644
index 0000000000..30ead90de9
--- /dev/null
+++ b/src/Umbraco.Tests/Models/ImageProcessorImageUrlGeneratorTest.cs
@@ -0,0 +1,232 @@
+using System;
+using System.Globalization;
+using Moq;
+using Newtonsoft.Json;
+using NUnit.Framework;
+using Newtonsoft.Json.Linq;
+using Umbraco.Core;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Configuration.UmbracoSettings;
+using Umbraco.Core.IO;
+using Umbraco.Core.Logging;
+using Umbraco.Core.Models;
+using Umbraco.Core.Models.PublishedContent;
+using Umbraco.Core.PropertyEditors;
+using Umbraco.Core.PropertyEditors.ValueConverters;
+using Umbraco.Core.Services;
+using Umbraco.Tests.Components;
+using Umbraco.Tests.TestHelpers;
+using Umbraco.Web.Models;
+using Umbraco.Web;
+using Umbraco.Web.PropertyEditors;
+using System.Text;
+
+namespace Umbraco.Tests.Models
+{
+ [TestFixture]
+ public class ImageProcessorImageUrlGeneratorTest
+ {
+ private const string MediaPath = "/media/1005/img_0671.jpg";
+ private static readonly ImageUrlGenerationOptions.CropCoordinates Crop = new ImageUrlGenerationOptions.CropCoordinates(0.58729977382575338m, 0.055768992440203169m, 0m, 0.32457553600198386m);
+ private static readonly ImageUrlGenerationOptions.FocalPointPosition Focus1 = new ImageUrlGenerationOptions.FocalPointPosition(0.80827067669172936m, 0.96m);
+ private static readonly ImageUrlGenerationOptions.FocalPointPosition Focus2 = new ImageUrlGenerationOptions.FocalPointPosition(0.41m, 0.4275m);
+ private static readonly ImageProcessorImageUrlGenerator Generator = new ImageProcessorImageUrlGenerator();
+
+ [Test]
+ public void GetCropUrl_CropAliasTest()
+ {
+ var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { Crop = Crop, Width = 100, Height = 100 });
+ Assert.AreEqual(MediaPath + "?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&width=100&height=100", urlString);
+ }
+
+ [Test]
+ public void GetCropUrl_WidthHeightTest()
+ {
+ var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = Focus1, Width = 200, Height = 300 });
+ Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&width=200&height=300", urlString);
+ }
+
+ [Test]
+ public void GetCropUrl_FocalPointTest()
+ {
+ var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = Focus1, Width = 100, Height = 100 });
+ Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&width=100&height=100", urlString);
+ }
+
+ [Test]
+ public void GetCropUrlFurtherOptionsTest()
+ {
+ var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = Focus1, Width = 200, Height = 300, FurtherOptions = "&filter=comic&roundedcorners=radius-26|bgcolor-fff" });
+ Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&width=200&height=300&filter=comic&roundedcorners=radius-26|bgcolor-fff", urlString);
+ }
+
+ ///
+ /// Test that if a crop alias has been specified that doesn't exist the method returns null
+ ///
+ [Test]
+ public void GetCropUrlNullTest()
+ {
+ var urlString = Generator.GetImageUrl(null);
+ Assert.AreEqual(null, urlString);
+ }
+
+ ///
+ /// Test that if a crop alias has been specified that doesn't exist the method returns null
+ ///
+ [Test]
+ public void GetCropUrlEmptyTest()
+ {
+ var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(null));
+ Assert.AreEqual("?mode=crop", urlString);
+ }
+
+ ///
+ /// Test the GetCropUrl method on the ImageCropDataSet Model
+ ///
+ [Test]
+ public void GetBaseCropUrlFromModelTest()
+ {
+ var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(null) { Crop = Crop, Width = 100, Height = 100 });
+ Assert.AreEqual("?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&width=100&height=100", urlString);
+ }
+
+ ///
+ /// Test the height ratio mode with predefined crop dimensions
+ ///
+ [Test]
+ public void GetCropUrl_CropAliasHeightRatioModeTest()
+ {
+ var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { Crop = Crop, Width = 100, HeightRatio = 1 });
+ Assert.AreEqual(MediaPath + "?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&heightratio=1&width=100", urlString);
+ }
+
+ ///
+ /// Test the height ratio mode with manual width/height dimensions
+ ///
+ [Test]
+ public void GetCropUrl_WidthHeightRatioModeTest()
+ {
+ var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = Focus1, Width = 300, HeightRatio = 0.5m });
+ Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&heightratio=0.5&width=300", urlString);
+ }
+
+ ///
+ /// Test the height ratio mode with width/height dimensions
+ ///
+ [Test]
+ public void GetCropUrl_HeightWidthRatioModeTest()
+ {
+ var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = Focus1, Height = 150, WidthRatio = 2 });
+ Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&widthratio=2&height=150", urlString);
+ }
+
+ ///
+ /// Test that if Crop mode is specified as anything other than Crop the image doesn't use the crop
+ ///
+ [Test]
+ public void GetCropUrl_SpecifiedCropModeTest()
+ {
+ var urlStringMin = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = "Min", Width = 300, Height = 150 });
+ var urlStringBoxPad = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = "BoxPad", Width = 300, Height = 150 });
+ var urlStringPad = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = "Pad", Width = 300, Height = 150 });
+ var urlStringMax = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = "Max", Width = 300, Height = 150 });
+ var urlStringStretch = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = "Stretch", Width = 300, Height = 150 });
+
+ Assert.AreEqual(MediaPath + "?mode=min&width=300&height=150", urlStringMin);
+ Assert.AreEqual(MediaPath + "?mode=boxpad&width=300&height=150", urlStringBoxPad);
+ Assert.AreEqual(MediaPath + "?mode=pad&width=300&height=150", urlStringPad);
+ Assert.AreEqual(MediaPath + "?mode=max&width=300&height=150", urlStringMax);
+ Assert.AreEqual(MediaPath + "?mode=stretch&width=300&height=150", urlStringStretch);
+ }
+
+ ///
+ /// Test for upload property type
+ ///
+ [Test]
+ public void GetCropUrl_UploadTypeTest()
+ {
+ var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = "Crop", ImageCropAnchor = "Center", Width = 100, Height = 270 });
+ Assert.AreEqual(MediaPath + "?mode=crop&anchor=center&width=100&height=270", urlString);
+ }
+
+ ///
+ /// Test for preferFocalPoint when focal point is centered
+ ///
+ [Test]
+ public void GetCropUrl_PreferFocalPointCenter()
+ {
+ var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { DefaultCrop = true, Width = 300, Height = 150 });
+ Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&width=300&height=150", urlString);
+ }
+
+ ///
+ /// Test to check if height ratio is returned for a predefined crop without coordinates and focal point in centre when a width parameter is passed
+ ///
+ [Test]
+ public void GetCropUrl_PreDefinedCropNoCoordinatesWithWidth()
+ {
+ var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { DefaultCrop = true, Width = 200, HeightRatio = 0.5962962962962962962962962963m });
+ Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&heightratio=0.5962962962962962962962962963&width=200", urlString);
+ }
+
+ ///
+ /// Test to check if height ratio is returned for a predefined crop without coordinates and focal point is custom when a width parameter is passed
+ ///
+ [Test]
+ public void GetCropUrl_PreDefinedCropNoCoordinatesWithWidthAndFocalPoint()
+ {
+ var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = Focus2, Width = 200, HeightRatio = 0.5962962962962962962962962963m });
+ Assert.AreEqual(MediaPath + "?center=0.41,0.4275&mode=crop&heightratio=0.5962962962962962962962962963&width=200", urlString);
+ }
+
+ ///
+ /// Test to check if crop ratio is ignored if useCropDimensions is true
+ ///
+ [Test]
+ public void GetCropUrl_PreDefinedCropNoCoordinatesWithWidthAndFocalPointIgnore()
+ {
+ var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { FocalPoint = Focus2, Width = 270, Height = 161 });
+ Assert.AreEqual(MediaPath + "?center=0.41,0.4275&mode=crop&width=270&height=161", urlString);
+ }
+
+ ///
+ /// Test to check if width ratio is returned for a predefined crop without coordinates and focal point in centre when a height parameter is passed
+ ///
+ [Test]
+ public void GetCropUrl_PreDefinedCropNoCoordinatesWithHeight()
+ {
+ var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { DefaultCrop = true, Height = 200, WidthRatio = 1.6770186335403726708074534161m });
+ Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&widthratio=1.6770186335403726708074534161&height=200", urlString);
+ }
+
+ ///
+ /// Test to check result when only a width parameter is passed, effectivly a resize only
+ ///
+ [Test]
+ public void GetCropUrl_WidthOnlyParameter()
+ {
+ var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { DefaultCrop = true, Width = 200 });
+ Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&width=200", urlString);
+ }
+
+ ///
+ /// Test to check result when only a height parameter is passed, effectivly a resize only
+ ///
+ [Test]
+ public void GetCropUrl_HeightOnlyParameter()
+ {
+ var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { DefaultCrop = true, Height = 200 });
+ Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&height=200", urlString);
+ }
+
+ ///
+ /// Test to check result when using a background color with padding
+ ///
+ [Test]
+ public void GetCropUrl_BackgroundColorParameter()
+ {
+ var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(MediaPath) { ImageCropMode = "Pad", Width = 400, Height = 400, FurtherOptions = "&bgcolor=fff" });
+ Assert.AreEqual(MediaPath + "?mode=pad&width=400&height=400&bgcolor=fff", urlString);
+ }
+ }
+}
diff --git a/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs b/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs
index f220387b75..281e5a9365 100644
--- a/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs
+++ b/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs
@@ -5,7 +5,6 @@ using Newtonsoft.Json;
using NUnit.Framework;
using Newtonsoft.Json.Linq;
using Umbraco.Core;
-using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
@@ -21,7 +20,9 @@ using Umbraco.Tests.TestHelpers;
using Umbraco.Web.Models;
using Umbraco.Web;
using Umbraco.Web.PropertyEditors;
+using System.Text;
using Current = Umbraco.Web.Composing.Current;
+using Umbraco.Core.Cache;
namespace Umbraco.Tests.PropertyEditors
{
@@ -113,8 +114,8 @@ namespace Umbraco.Tests.PropertyEditors
[Test]
public void GetCropUrl_CropAliasTest()
{
- var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, cropAlias: "Thumb", useCropDimensions: true);
- Assert.AreEqual(MediaPath + "?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&width=100&height=100", urlString);
+ var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, cropAlias: "Thumb", useCropDimensions: true);
+ Assert.AreEqual(MediaPath + "?c=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&w=100&h=100", urlString);
}
///
@@ -123,29 +124,29 @@ namespace Umbraco.Tests.PropertyEditors
[Test]
public void GetCropUrl_CropAliasIgnoreWidthHeightTest()
{
- var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, cropAlias: "Thumb", useCropDimensions: true, width: 50, height: 50);
- Assert.AreEqual(MediaPath + "?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&width=100&height=100", urlString);
+ var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, cropAlias: "Thumb", useCropDimensions: true, width: 50, height: 50);
+ Assert.AreEqual(MediaPath + "?c=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&w=100&h=100", urlString);
}
[Test]
public void GetCropUrl_WidthHeightTest()
{
- var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, width: 200, height: 300);
- Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&width=200&height=300", urlString);
+ var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, width: 200, height: 300);
+ Assert.AreEqual(MediaPath + "?f=0.80827067669172936x0.96&w=200&h=300", urlString);
}
[Test]
public void GetCropUrl_FocalPointTest()
{
- var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, cropAlias: "thumb", preferFocalPoint: true, useCropDimensions: true);
- Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&width=100&height=100", urlString);
+ var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, cropAlias: "thumb", preferFocalPoint: true, useCropDimensions: true);
+ Assert.AreEqual(MediaPath + "?f=0.80827067669172936x0.96&w=100&h=100", urlString);
}
[Test]
public void GetCropUrlFurtherOptionsTest()
{
- var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, width: 200, height: 300, furtherOptions: "&filter=comic&roundedcorners=radius-26|bgcolor-fff");
- Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&width=200&height=300&filter=comic&roundedcorners=radius-26|bgcolor-fff", urlString);
+ var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, width: 200, height: 300, furtherOptions: "&filter=comic&roundedcorners=radius-26|bgcolor-fff");
+ Assert.AreEqual(MediaPath + "?f=0.80827067669172936x0.96&w=200&h=300&filter=comic&roundedcorners=radius-26|bgcolor-fff", urlString);
}
///
@@ -154,7 +155,7 @@ namespace Umbraco.Tests.PropertyEditors
[Test]
public void GetCropUrlNullTest()
{
- var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, cropAlias: "Banner", useCropDimensions: true);
+ var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, cropAlias: "Banner", useCropDimensions: true);
Assert.AreEqual(null, urlString);
}
@@ -165,8 +166,8 @@ namespace Umbraco.Tests.PropertyEditors
public void GetBaseCropUrlFromModelTest()
{
var cropDataSet = CropperJson1.DeserializeImageCropperValue();
- var urlString = cropDataSet.GetCropUrl("thumb");
- Assert.AreEqual("?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&width=100&height=100", urlString);
+ var urlString = cropDataSet.GetCropUrl("thumb", new TestImageUrlGenerator());
+ Assert.AreEqual("?c=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&w=100&h=100", urlString);
}
///
@@ -175,8 +176,8 @@ namespace Umbraco.Tests.PropertyEditors
[Test]
public void GetCropUrl_CropAliasHeightRatioModeTest()
{
- var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, cropAlias: "Thumb", useCropDimensions: true, ratioMode:ImageCropRatioMode.Height);
- Assert.AreEqual(MediaPath + "?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&width=100&heightratio=1", urlString);
+ var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, cropAlias: "Thumb", useCropDimensions: true, ratioMode:ImageCropRatioMode.Height);
+ Assert.AreEqual(MediaPath + "?c=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&hr=1&w=100", urlString);
}
///
@@ -185,8 +186,8 @@ namespace Umbraco.Tests.PropertyEditors
[Test]
public void GetCropUrl_WidthHeightRatioModeTest()
{
- var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, width: 300, height: 150, ratioMode:ImageCropRatioMode.Height);
- Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&width=300&heightratio=0.5", urlString);
+ var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, width: 300, height: 150, ratioMode:ImageCropRatioMode.Height);
+ Assert.AreEqual(MediaPath + "?f=0.80827067669172936x0.96&hr=0.5&w=300", urlString);
}
///
@@ -195,8 +196,8 @@ namespace Umbraco.Tests.PropertyEditors
[Test]
public void GetCropUrl_HeightWidthRatioModeTest()
{
- var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, width: 300, height: 150, ratioMode: ImageCropRatioMode.Width);
- Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&height=150&widthratio=2", urlString);
+ var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, width: 300, height: 150, ratioMode: ImageCropRatioMode.Width);
+ Assert.AreEqual(MediaPath + "?f=0.80827067669172936x0.96&wr=2&h=150", urlString);
}
///
@@ -205,17 +206,17 @@ namespace Umbraco.Tests.PropertyEditors
[Test]
public void GetCropUrl_SpecifiedCropModeTest()
{
- var urlStringMin = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.Min);
- var urlStringBoxPad = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.BoxPad);
- var urlStringPad = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.Pad);
- var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, width: 300, height: 150, imageCropMode:ImageCropMode.Max);
- var urlStringStretch = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.Stretch);
+ var urlStringMin = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.Min);
+ var urlStringBoxPad = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.BoxPad);
+ var urlStringPad = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.Pad);
+ var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, width: 300, height: 150, imageCropMode:ImageCropMode.Max);
+ var urlStringStretch = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.Stretch);
- Assert.AreEqual(MediaPath + "?mode=min&width=300&height=150", urlStringMin);
- Assert.AreEqual(MediaPath + "?mode=boxpad&width=300&height=150", urlStringBoxPad);
- Assert.AreEqual(MediaPath + "?mode=pad&width=300&height=150", urlStringPad);
- Assert.AreEqual(MediaPath + "?mode=max&width=300&height=150", urlString);
- Assert.AreEqual(MediaPath + "?mode=stretch&width=300&height=150", urlStringStretch);
+ Assert.AreEqual(MediaPath + "?m=min&w=300&h=150", urlStringMin);
+ Assert.AreEqual(MediaPath + "?m=boxpad&w=300&h=150", urlStringBoxPad);
+ Assert.AreEqual(MediaPath + "?m=pad&w=300&h=150", urlStringPad);
+ Assert.AreEqual(MediaPath + "?m=max&w=300&h=150", urlString);
+ Assert.AreEqual(MediaPath + "?m=stretch&w=300&h=150", urlStringStretch);
}
///
@@ -224,8 +225,8 @@ namespace Umbraco.Tests.PropertyEditors
[Test]
public void GetCropUrl_UploadTypeTest()
{
- var urlString = MediaPath.GetCropUrl(width: 100, height: 270, imageCropMode: ImageCropMode.Crop, imageCropAnchor: ImageCropAnchor.Center);
- Assert.AreEqual(MediaPath + "?mode=crop&anchor=center&width=100&height=270", urlString);
+ var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), width: 100, height: 270, imageCropMode: ImageCropMode.Crop, imageCropAnchor: ImageCropAnchor.Center);
+ Assert.AreEqual(MediaPath + "?m=crop&a=center&w=100&h=270", urlString);
}
///
@@ -236,8 +237,8 @@ namespace Umbraco.Tests.PropertyEditors
{
const string cropperJson = "{\"focalPoint\": {\"left\": 0.5,\"top\": 0.5},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\":\"thumb\",\"width\": 100,\"height\": 100,\"coordinates\": {\"x1\": 0.58729977382575338,\"y1\": 0.055768992440203169,\"x2\": 0,\"y2\": 0.32457553600198386}}]}";
- var urlString = MediaPath.GetCropUrl(imageCropperValue: cropperJson, width: 300, height: 150, preferFocalPoint:true);
- Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&width=300&height=150", urlString);
+ var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: cropperJson, width: 300, height: 150, preferFocalPoint:true);
+ Assert.AreEqual(MediaPath + "?m=defaultcrop&w=300&h=150", urlString);
}
///
@@ -248,8 +249,8 @@ namespace Umbraco.Tests.PropertyEditors
{
const string cropperJson = "{\"focalPoint\": {\"left\": 0.5,\"top\": 0.5},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\": \"home\",\"width\": 270,\"height\": 161}]}";
- var urlString = MediaPath.GetCropUrl(imageCropperValue: cropperJson, cropAlias: "home", width: 200);
- Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&heightratio=0.5962962962962962962962962963&width=200", urlString);
+ var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: cropperJson, cropAlias: "home", width: 200);
+ Assert.AreEqual(MediaPath + "?m=defaultcrop&hr=0.5962962962962962962962962963&w=200", urlString);
}
///
@@ -260,8 +261,8 @@ namespace Umbraco.Tests.PropertyEditors
{
const string cropperJson = "{\"focalPoint\": {\"left\": 0.4275,\"top\": 0.41},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\": \"home\",\"width\": 270,\"height\": 161}]}";
- var urlString = MediaPath.GetCropUrl(imageCropperValue: cropperJson, cropAlias: "home", width: 200);
- Assert.AreEqual(MediaPath + "?center=0.41,0.4275&mode=crop&heightratio=0.5962962962962962962962962963&width=200", urlString);
+ var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: cropperJson, cropAlias: "home", width: 200);
+ Assert.AreEqual(MediaPath + "?f=0.41x0.4275&hr=0.5962962962962962962962962963&w=200", urlString);
}
///
@@ -272,8 +273,8 @@ namespace Umbraco.Tests.PropertyEditors
{
const string cropperJson = "{\"focalPoint\": {\"left\": 0.4275,\"top\": 0.41},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\": \"home\",\"width\": 270,\"height\": 161}]}";
- var urlString = MediaPath.GetCropUrl(imageCropperValue: cropperJson, cropAlias: "home", width: 200, useCropDimensions: true);
- Assert.AreEqual(MediaPath + "?center=0.41,0.4275&mode=crop&width=270&height=161", urlString);
+ var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: cropperJson, cropAlias: "home", width: 200, useCropDimensions: true);
+ Assert.AreEqual(MediaPath + "?f=0.41x0.4275&w=270&h=161", urlString);
}
///
@@ -284,8 +285,8 @@ namespace Umbraco.Tests.PropertyEditors
{
const string cropperJson = "{\"focalPoint\": {\"left\": 0.5,\"top\": 0.5},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\": \"home\",\"width\": 270,\"height\": 161}]}";
- var urlString = MediaPath.GetCropUrl(imageCropperValue: cropperJson, cropAlias: "home", height: 200);
- Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&widthratio=1.6770186335403726708074534161&height=200", urlString);
+ var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: cropperJson, cropAlias: "home", height: 200);
+ Assert.AreEqual(MediaPath + "?m=defaultcrop&wr=1.6770186335403726708074534161&h=200", urlString);
}
///
@@ -296,8 +297,8 @@ namespace Umbraco.Tests.PropertyEditors
{
const string cropperJson = "{\"focalPoint\": {\"left\": 0.5,\"top\": 0.5},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\": \"home\",\"width\": 270,\"height\": 161}]}";
- var urlString = MediaPath.GetCropUrl(imageCropperValue: cropperJson, width: 200);
- Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&width=200", urlString);
+ var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: cropperJson, width: 200);
+ Assert.AreEqual(MediaPath + "?m=defaultcrop&w=200", urlString);
}
///
@@ -308,8 +309,8 @@ namespace Umbraco.Tests.PropertyEditors
{
const string cropperJson = "{\"focalPoint\": {\"left\": 0.5,\"top\": 0.5},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\": \"home\",\"width\": 270,\"height\": 161}]}";
- var urlString = MediaPath.GetCropUrl(imageCropperValue: cropperJson, height: 200);
- Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&height=200", urlString);
+ var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: cropperJson, height: 200);
+ Assert.AreEqual(MediaPath + "?m=defaultcrop&h=200", urlString);
}
///
@@ -320,8 +321,55 @@ namespace Umbraco.Tests.PropertyEditors
{
var cropperJson = "{\"focalPoint\": {\"left\": 0.5,\"top\": 0.5},\"src\": \"" + MediaPath + "\",\"crops\": [{\"alias\": \"home\",\"width\": 270,\"height\": 161}]}";
- var urlString = MediaPath.GetCropUrl(400, 400, cropperJson, imageCropMode: ImageCropMode.Pad, furtherOptions: "&bgcolor=fff");
- Assert.AreEqual(MediaPath + "?mode=pad&width=400&height=400&bgcolor=fff", urlString);
+ var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), 400, 400, cropperJson, imageCropMode: ImageCropMode.Pad, furtherOptions: "&bgcolor=fff");
+ Assert.AreEqual(MediaPath + "?m=pad&w=400&h=400&bgcolor=fff", urlString);
+ }
+
+ internal class TestImageUrlGenerator : IImageUrlGenerator
+ {
+ public string GetImageUrl(ImageUrlGenerationOptions options)
+ {
+ var imageProcessorUrl = new StringBuilder(options.ImageUrl ?? string.Empty);
+
+ if (options.FocalPoint != null)
+ {
+ imageProcessorUrl.Append("?f=");
+ imageProcessorUrl.Append(options.FocalPoint.Top.ToString(CultureInfo.InvariantCulture));
+ imageProcessorUrl.Append("x");
+ imageProcessorUrl.Append(options.FocalPoint.Left.ToString(CultureInfo.InvariantCulture));
+ }
+ else if (options.Crop != null)
+ {
+ imageProcessorUrl.Append("?c=");
+ imageProcessorUrl.Append(options.Crop.X1.ToString(CultureInfo.InvariantCulture)).Append(",");
+ imageProcessorUrl.Append(options.Crop.Y1.ToString(CultureInfo.InvariantCulture)).Append(",");
+ imageProcessorUrl.Append(options.Crop.X2.ToString(CultureInfo.InvariantCulture)).Append(",");
+ imageProcessorUrl.Append(options.Crop.Y2.ToString(CultureInfo.InvariantCulture));
+ }
+ else if (options.DefaultCrop)
+ {
+ imageProcessorUrl.Append("?m=defaultcrop");
+ }
+ else
+ {
+ imageProcessorUrl.Append("?m=" + options.ImageCropMode.ToString().ToLower());
+ if (options.ImageCropAnchor != null)imageProcessorUrl.Append("&a=" + options.ImageCropAnchor.ToString().ToLower());
+ }
+
+ var hasFormat = options.FurtherOptions != null && options.FurtherOptions.InvariantContains("&f=");
+ if (options.Quality != null && hasFormat == false) imageProcessorUrl.Append("&q=" + options.Quality);
+ if (options.HeightRatio != null) imageProcessorUrl.Append("&hr=" + options.HeightRatio.Value.ToString(CultureInfo.InvariantCulture));
+ if (options.WidthRatio != null) imageProcessorUrl.Append("&wr=" + options.WidthRatio.Value.ToString(CultureInfo.InvariantCulture));
+ if (options.Width != null) imageProcessorUrl.Append("&w=" + options.Width);
+ if (options.Height != null) imageProcessorUrl.Append("&h=" + options.Height);
+ if (options.UpScale == false) imageProcessorUrl.Append("&u=no");
+ if (options.AnimationProcessMode != null) imageProcessorUrl.Append("&apm=" + options.AnimationProcessMode);
+ if (options.FurtherOptions != null) imageProcessorUrl.Append(options.FurtherOptions);
+ if (options.Quality != null && hasFormat) imageProcessorUrl.Append("&q=" + options.Quality);
+ if (options.CacheBusterValue != null) imageProcessorUrl.Append("&r=").Append(options.CacheBusterValue);
+
+ return imageProcessorUrl.ToString();
+ }
}
}
}
diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs
index 177561d1ea..ee62bbe06f 100644
--- a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs
+++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs
@@ -14,6 +14,7 @@ using Umbraco.Core.Services;
using Umbraco.Core.Strings;
using Umbraco.Web;
using Umbraco.Web.Templates;
+using Umbraco.Web.Models;
namespace Umbraco.Tests.PublishedContent
{
@@ -60,7 +61,8 @@ namespace Umbraco.Tests.PublishedContent
pastedImages,
ShortStringHelper,
IOHelper,
- LocalizedTextService)) { Id = 1 });
+ LocalizedTextService,
+ Mock.Of())) { Id = 1 });
var publishedContentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeService);
diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs
index 5c03a0721d..9a0527af2c 100644
--- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs
+++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs
@@ -22,6 +22,7 @@ using Umbraco.Tests.Testing;
using Umbraco.Web.Models.PublishedContent;
using Umbraco.Web.PropertyEditors;
using Umbraco.Web.Templates;
+using Umbraco.Web.Models;
using Current = Umbraco.Web.Composing.Current;
namespace Umbraco.Tests.PublishedContent
@@ -56,7 +57,7 @@ namespace Umbraco.Tests.PublishedContent
var dataTypeService = new TestObjects.TestDataTypeService(
new DataType(new VoidEditor(logger, Mock.Of(), localizationService, LocalizedTextService, ShortStringHelper)) { Id = 1 },
new DataType(new TrueFalsePropertyEditor(logger, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService)) { Id = 1001 },
- new DataType(new RichTextPropertyEditor(logger, mediaService, contentTypeBaseServiceProvider, umbracoContextAccessor, Mock.Of(), localizationService, imageSourceParser, linkParser, pastedImages, ShortStringHelper, IOHelper, LocalizedTextService)) { Id = 1002 },
+ new DataType(new RichTextPropertyEditor(logger, mediaService, contentTypeBaseServiceProvider, umbracoContextAccessor, Mock.Of(), localizationService, imageSourceParser, linkParser, pastedImages, ShortStringHelper, IOHelper, LocalizedTextService, Mock.Of())) { Id = 1002 },
new DataType(new IntegerPropertyEditor(logger, Mock.Of(), localizationService, ShortStringHelper, LocalizedTextService)) { Id = 1003 },
new DataType(new TextboxPropertyEditor(logger, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService)) { Id = 1004 },
new DataType(new MediaPickerPropertyEditor(logger, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService)) { Id = 1005 });
diff --git a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs
index 27113bdc79..b0e0c1138b 100644
--- a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs
+++ b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs
@@ -106,6 +106,7 @@ namespace Umbraco.Tests.Runtimes
composition.Register(Lifetime.Singleton);
composition.Register(_ => Mock.Of(), Lifetime.Singleton);
composition.RegisterUnique(f => new DistributedCache(f.GetInstance(), f.GetInstance()));
+ composition.Register(_ => Mock.Of(), Lifetime.Singleton);
composition.WithCollectionBuilder().Append();
composition.RegisterUnique();
composition.RegisterUnique();
diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
index a1d50e54c1..4b21e11ff4 100644
--- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
+++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
@@ -48,6 +48,7 @@ using FileSystems = Umbraco.Core.IO.FileSystems;
using Umbraco.Web.Templates;
using Umbraco.Web.PropertyEditors;
using Umbraco.Core.Dictionary;
+using Umbraco.Core.Models;
using Umbraco.Core.Models.Identity;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
@@ -304,6 +305,7 @@ namespace Umbraco.Tests.Testing
var runtimeStateMock = new Mock();
runtimeStateMock.Setup(x => x.Level).Returns(RuntimeLevel.Run);
Composition.RegisterUnique(f => runtimeStateMock.Object);
+ Composition.Register(_ => Mock.Of());
// ah...
Composition.WithCollectionBuilder();
diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj
index 31cc85e5c5..16e4ca2c11 100644
--- a/src/Umbraco.Tests/Umbraco.Tests.csproj
+++ b/src/Umbraco.Tests/Umbraco.Tests.csproj
@@ -142,6 +142,7 @@
+
diff --git a/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs
index 0c9b4f428f..0dec6560b8 100644
--- a/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs
+++ b/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs
@@ -90,7 +90,8 @@ namespace Umbraco.Tests.Web.Controllers
ShortStringHelper,
Factory.GetInstance(),
Factory.GetInstance(),
- Factory.GetInstance()
+ Factory.GetInstance(),
+ Factory.GetInstance()
);
return usersController;
}
@@ -160,7 +161,8 @@ namespace Umbraco.Tests.Web.Controllers
ShortStringHelper,
Factory.GetInstance(),
Factory.GetInstance(),
- Factory.GetInstance()
+ Factory.GetInstance(),
+ Factory.GetInstance()
);
return usersController;
}
@@ -201,7 +203,8 @@ namespace Umbraco.Tests.Web.Controllers
ShortStringHelper,
Factory.GetInstance(),
Factory.GetInstance(),
- Factory.GetInstance()
+ Factory.GetInstance(),
+ Factory.GetInstance()
);
return usersController;
}
@@ -277,7 +280,8 @@ namespace Umbraco.Tests.Web.Controllers
ShortStringHelper,
Factory.GetInstance(),
Factory.GetInstance(),
- Factory.GetInstance()
+ Factory.GetInstance(),
+ Factory.GetInstance()
);
return usersController;
}
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/imageurlgenerator.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/imageurlgenerator.resource.js
new file mode 100644
index 0000000000..a937cd2675
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/imageurlgenerator.resource.js
@@ -0,0 +1,36 @@
+/**
+ * @ngdoc service
+ * @name umbraco.resources.imageUrlGeneratorResource
+ * @function
+ *
+ * @description
+ * Used by the various controllers to get an image URL formatted correctly for the current image URL generator
+ */
+(function () {
+ 'use strict';
+
+ function imageUrlGeneratorResource($http, umbRequestHelper) {
+
+ function getCropUrl(mediaPath, width, height, imageCropMode, animationProcessMode) {
+
+ return umbRequestHelper.resourcePromise(
+ $http.get(
+ umbRequestHelper.getApiUrl(
+ "imageUrlGeneratorApiBaseUrl",
+ "GetCropUrl",
+ { mediaPath, width, height, imageCropMode, animationProcessMode })),
+ 'Failed to get crop URL');
+ }
+
+
+ var resource = {
+ getCropUrl: getCropUrl
+ };
+
+ return resource;
+
+ }
+
+ angular.module('umbraco.resources').factory('imageUrlGeneratorResource', imageUrlGeneratorResource);
+
+})();
diff --git a/src/Umbraco.Web.UI.Client/src/less/sections.less b/src/Umbraco.Web.UI.Client/src/less/sections.less
index 40921c5b76..27b11b1c3b 100644
--- a/src/Umbraco.Web.UI.Client/src/less/sections.less
+++ b/src/Umbraco.Web.UI.Client/src/less/sections.less
@@ -41,13 +41,13 @@ ul.sections {
&:focus .section__name {
.tabbing-active & {
- border: 1px solid;
- border-color: @gray-9;
+ border: 1px solid @gray-9;
}
}
}
.section__name {
+ border: 1px solid transparent;
border-radius: 3px;
margin-top: 1px;
padding: 3px 10px 4px 10px;
@@ -75,9 +75,9 @@ ul.sections {
opacity: 0.6;
transition: opacity .1s linear;
}
-
+
&:hover i {
- opacity:1;
+ opacity: 1;
}
}
diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Gallery.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Gallery.cshtml
index 7ff9d0bb94..7962d17898 100755
--- a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Gallery.cshtml
+++ b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Gallery.cshtml
@@ -1,6 +1,7 @@
@using Umbraco.Core.Models.PublishedContent
@using Umbraco.Web
@using Umbraco.Core
+@using Umbraco.Core.Models
@using Umbraco.Web.Composing
@inherits Umbraco.Web.Macros.PartialViewMacroPage
@@ -46,7 +47,7 @@
{
}
diff --git a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Media.cshtml b/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Media.cshtml
index ea79ce41ad..0ed54ab958 100644
--- a/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Media.cshtml
+++ b/src/Umbraco.Web.UI/Views/Partials/Grid/Editors/Media.cshtml
@@ -2,20 +2,24 @@
@using Umbraco.Web.Templates
@if (Model.value != null)
-{
+{
var url = Model.value.image;
if(Model.editor.config != null && Model.editor.config.size != null){
- url += "?width=" + Model.editor.config.size.width;
- url += "&height=" + Model.editor.config.size.height;
-
- if(Model.value.focalPoint != null){
- url += "¢er=" + Model.value.focalPoint.top +"," + Model.value.focalPoint.left;
- url += "&mode=crop";
- }
+ url = ImageCropperTemplateCoreExtensions.GetCropUrl(url, Umbraco.Web.Composing.Current.Factory.GetInstance(),
+ width: Model.editor.config.size.width,
+ height: Model.editor.config.size.height,
+ cropDataSet: Model.value.focalPoint == null ? null : new Umbraco.Core.PropertyEditors.ValueConverters.ImageCropperValue
+ {
+ FocalPoint = new Umbraco.Core.PropertyEditors.ValueConverters.ImageCropperValue.ImageCropperFocalPoint
+ {
+ Top = Model.value.focalPoint.top,
+ Left = Model.value.focalPoint.left
+ }
+ });
}
var altText = Model.value.altText ?? Model.value.caption ?? string.Empty;
-
+
if (Model.value.caption != null)
diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
index 0a545a2b2d..9d2f59821d 100644
--- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
+++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs
@@ -321,6 +321,10 @@ namespace Umbraco.Web.Editors
"tinyMceApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
controller => controller.UploadImage())
},
+ {
+ "imageUrlGeneratorApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl(
+ controller => controller.GetCropUrl(null, null, null, null, null))
+ },
}
},
{
diff --git a/src/Umbraco.Web/Editors/CurrentUserController.cs b/src/Umbraco.Web/Editors/CurrentUserController.cs
index f57237356b..94406d828b 100644
--- a/src/Umbraco.Web/Editors/CurrentUserController.cs
+++ b/src/Umbraco.Web/Editors/CurrentUserController.cs
@@ -22,6 +22,7 @@ using Umbraco.Web.Security;
using Umbraco.Web.WebApi.Filters;
using Umbraco.Core.Mapping;
using Umbraco.Core.Configuration.UmbracoSettings;
+using Umbraco.Core.Models;
namespace Umbraco.Web.Editors
{
@@ -34,6 +35,7 @@ namespace Umbraco.Web.Editors
private readonly IMediaFileSystem _mediaFileSystem;
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
private readonly IIOHelper _ioHelper;
+ private readonly IImageUrlGenerator _imageUrlGenerator;
public CurrentUserController(
IGlobalSettings globalSettings,
@@ -48,12 +50,14 @@ namespace Umbraco.Web.Editors
IShortStringHelper shortStringHelper,
UmbracoMapper umbracoMapper,
IUmbracoSettingsSection umbracoSettingsSection,
- IIOHelper ioHelper)
+ IIOHelper ioHelper,
+ IImageUrlGenerator imageUrlGenerator)
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper, shortStringHelper, umbracoMapper)
{
_mediaFileSystem = mediaFileSystem;
_umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection));
_ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper));
+ _imageUrlGenerator = imageUrlGenerator;
}
///
@@ -187,7 +191,7 @@ namespace Umbraco.Web.Editors
public async Task PostSetAvatar()
{
//borrow the logic from the user controller
- return await UsersController.PostSetAvatarInternal(Request, Services.UserService, AppCaches.RuntimeCache, _mediaFileSystem, ShortStringHelper, _umbracoSettingsSection, _ioHelper, Security.GetUserId().ResultOr(0));
+ return await UsersController.PostSetAvatarInternal(Request, Services.UserService, AppCaches.RuntimeCache, _mediaFileSystem, ShortStringHelper, _umbracoSettingsSection, _ioHelper, _imageUrlGenerator, Security.GetUserId().ResultOr(0));
}
///
diff --git a/src/Umbraco.Web/Editors/ImageUrlGeneratorController.cs b/src/Umbraco.Web/Editors/ImageUrlGeneratorController.cs
new file mode 100644
index 0000000000..87d7e29619
--- /dev/null
+++ b/src/Umbraco.Web/Editors/ImageUrlGeneratorController.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Umbraco.Core.Models;
+using Umbraco.Web.Models;
+using Umbraco.Web.Mvc;
+
+namespace Umbraco.Web.Editors
+{
+ ///
+ /// The API controller used for getting URLs for images with parameters
+ ///
+ ///
+ ///
+ /// This controller allows for retrieving URLs for processed images, such as resized, cropped,
+ /// or otherwise altered. These can be different based on the IImageUrlGenerator
+ /// implementation in use, and so the BackOffice could should not rely on hard-coded string
+ /// building to generate correct URLs
+ ///
+ ///
+ public class ImageUrlGeneratorController : UmbracoAuthorizedJsonController
+ {
+ private readonly IImageUrlGenerator _imageUrlGenerator;
+
+ public ImageUrlGeneratorController(IImageUrlGenerator imageUrlGenerator)
+ {
+ _imageUrlGenerator = imageUrlGenerator;
+ }
+
+ public string GetCropUrl(string mediaPath, int? width = null, int? height = null, ImageCropMode? imageCropMode = null, string animationProcessMode = null)
+ {
+ return mediaPath.GetCropUrl(_imageUrlGenerator, null, width: width, height: height, imageCropMode: imageCropMode, animationProcessMode: animationProcessMode);
+ }
+ }
+}
diff --git a/src/Umbraco.Web/Editors/ImagesController.cs b/src/Umbraco.Web/Editors/ImagesController.cs
index d3fc3ee947..d9a28c70c4 100644
--- a/src/Umbraco.Web/Editors/ImagesController.cs
+++ b/src/Umbraco.Web/Editors/ImagesController.cs
@@ -4,7 +4,7 @@ using System.Net;
using System.Net.Http;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
-using Umbraco.Web.Media;
+using Umbraco.Core.Models;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi;
@@ -18,11 +18,13 @@ namespace Umbraco.Web.Editors
{
private readonly IMediaFileSystem _mediaFileSystem;
private readonly IContentSection _contentSection;
+ private readonly IImageUrlGenerator _imageUrlGenerator;
- public ImagesController(IMediaFileSystem mediaFileSystem, IContentSection contentSection)
+ public ImagesController(IMediaFileSystem mediaFileSystem, IContentSection contentSection, IImageUrlGenerator imageUrlGenerator)
{
_mediaFileSystem = mediaFileSystem;
_contentSection = contentSection;
+ _imageUrlGenerator = imageUrlGenerator;
}
///
@@ -74,12 +76,10 @@ namespace Umbraco.Web.Editors
// so ignore and we won't set a last modified date.
}
- // TODO: When we abstract imaging for netcore, we are actually just going to be abstracting a URI builder for images, this
- // is one of those places where this can be used.
+ var rnd = imageLastModified.HasValue ? $"&rnd={imageLastModified:yyyyMMddHHmmss}" : null;
+ var imageUrl = _imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(imagePath) { UpScale = false, Width = width, AnimationProcessMode = "first", ImageCropMode = "max", CacheBusterValue = rnd });
- var rnd = imageLastModified.HasValue ? $"&rnd={imageLastModified:yyyyMMddHHmmss}" : string.Empty;
-
- response.Headers.Location = new Uri($"{imagePath}?upscale=false&width={width}&animationprocessmode=first&mode=max{rnd}", UriKind.RelativeOrAbsolute);
+ response.Headers.Location = new Uri(imageUrl, UriKind.RelativeOrAbsolute);
return response;
}
diff --git a/src/Umbraco.Web/Editors/LogController.cs b/src/Umbraco.Web/Editors/LogController.cs
index 9493c9eaa1..0f7f19e658 100644
--- a/src/Umbraco.Web/Editors/LogController.cs
+++ b/src/Umbraco.Web/Editors/LogController.cs
@@ -24,6 +24,7 @@ namespace Umbraco.Web.Editors
public class LogController : UmbracoAuthorizedJsonController
{
private readonly IMediaFileSystem _mediaFileSystem;
+ private readonly IImageUrlGenerator _imageUrlGenerator;
public LogController(
IGlobalSettings globalSettings,
@@ -36,10 +37,12 @@ namespace Umbraco.Web.Editors
UmbracoHelper umbracoHelper,
IMediaFileSystem mediaFileSystem,
IShortStringHelper shortStringHelper,
- UmbracoMapper umbracoMapper)
+ UmbracoMapper umbracoMapper,
+ IImageUrlGenerator imageUrlGenerator)
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper, shortStringHelper, umbracoMapper)
{
_mediaFileSystem = mediaFileSystem;
+ _imageUrlGenerator = imageUrlGenerator;
}
[UmbracoApplicationAuthorize(Core.Constants.Applications.Content, Core.Constants.Applications.Media)]
@@ -94,7 +97,7 @@ namespace Umbraco.Web.Editors
var mappedItems = items.ToList();
var userIds = mappedItems.Select(x => x.UserId).ToArray();
var userAvatars = Services.UserService.GetUsersById(userIds)
- .ToDictionary(x => x.Id, x => x.GetUserAvatarUrls(AppCaches.RuntimeCache, _mediaFileSystem));
+ .ToDictionary(x => x.Id, x => x.GetUserAvatarUrls(AppCaches.RuntimeCache, _mediaFileSystem, _imageUrlGenerator));
var userNames = Services.UserService.GetUsersById(userIds).ToDictionary(x => x.Id, x => x.Name);
foreach (var item in mappedItems)
{
diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs
index 358ac1f2b8..822e44bce8 100644
--- a/src/Umbraco.Web/Editors/UsersController.cs
+++ b/src/Umbraco.Web/Editors/UsersController.cs
@@ -48,6 +48,7 @@ namespace Umbraco.Web.Editors
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
private readonly IIOHelper _ioHelper;
private readonly ISqlContext _sqlContext;
+ private readonly IImageUrlGenerator _imageUrlGenerator;
public UsersController(
IGlobalSettings globalSettings,
@@ -62,13 +63,15 @@ namespace Umbraco.Web.Editors
IShortStringHelper shortStringHelper,
UmbracoMapper umbracoMapper,
IUmbracoSettingsSection umbracoSettingsSection,
- IIOHelper ioHelper)
+ IIOHelper ioHelper,
+ IImageUrlGenerator imageUrlGenerator)
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper, shortStringHelper, umbracoMapper)
{
_mediaFileSystem = mediaFileSystem;
_umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection));
_ioHelper = ioHelper;
_sqlContext = sqlContext;
+ _imageUrlGenerator = imageUrlGenerator;
}
///
@@ -77,7 +80,7 @@ namespace Umbraco.Web.Editors
///
public string[] GetCurrentUserAvatarUrls()
{
- var urls = UmbracoContext.Security.CurrentUser.GetUserAvatarUrls(AppCaches.RuntimeCache, _mediaFileSystem);
+ var urls = UmbracoContext.Security.CurrentUser.GetUserAvatarUrls(AppCaches.RuntimeCache, _mediaFileSystem, _imageUrlGenerator);
if (urls == null)
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Could not access Gravatar endpoint"));
@@ -89,10 +92,10 @@ namespace Umbraco.Web.Editors
[AdminUsersAuthorize]
public async Task PostSetAvatar(int id)
{
- return await PostSetAvatarInternal(Request, Services.UserService, AppCaches.RuntimeCache, _mediaFileSystem, ShortStringHelper, _umbracoSettingsSection, _ioHelper, id);
+ return await PostSetAvatarInternal(Request, Services.UserService, AppCaches.RuntimeCache, _mediaFileSystem, ShortStringHelper, _umbracoSettingsSection, _ioHelper, _imageUrlGenerator, id);
}
- internal static async Task PostSetAvatarInternal(HttpRequestMessage request, IUserService userService, IAppCache cache, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, IUmbracoSettingsSection umbracoSettingsSection, IIOHelper ioHelper, int id)
+ internal static async Task PostSetAvatarInternal(HttpRequestMessage request, IUserService userService, IAppCache cache, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, IUmbracoSettingsSection umbracoSettingsSection, IIOHelper ioHelper, IImageUrlGenerator imageUrlGenerator, int id)
{
if (request.Content.IsMimeMultipartContent() == false)
{
@@ -146,7 +149,7 @@ namespace Umbraco.Web.Editors
});
}
- return request.CreateResponse(HttpStatusCode.OK, user.GetUserAvatarUrls(cache, mediaFileSystem));
+ return request.CreateResponse(HttpStatusCode.OK, user.GetUserAvatarUrls(cache, mediaFileSystem, imageUrlGenerator));
}
[AppendUserModifiedHeader("id")]
@@ -180,7 +183,7 @@ namespace Umbraco.Web.Editors
_mediaFileSystem.DeleteFile(filePath);
}
- return Request.CreateResponse(HttpStatusCode.OK, found.GetUserAvatarUrls(AppCaches.RuntimeCache, _mediaFileSystem));
+ return Request.CreateResponse(HttpStatusCode.OK, found.GetUserAvatarUrls(AppCaches.RuntimeCache, _mediaFileSystem, _imageUrlGenerator));
}
///
diff --git a/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs b/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs
new file mode 100644
index 0000000000..7ac5578d75
--- /dev/null
+++ b/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs
@@ -0,0 +1,379 @@
+using System;
+using Newtonsoft.Json.Linq;
+using System.Globalization;
+using Umbraco.Core;
+using Umbraco.Core.Models;
+using Umbraco.Core.Models.PublishedContent;
+using Umbraco.Core.PropertyEditors.ValueConverters;
+using Umbraco.Web.Models;
+
+namespace Umbraco.Web
+{
+ public static class ImageCropperTemplateCoreExtensions
+ {
+ ///
+ /// Gets the ImageProcessor Url by the crop alias (from the "umbracoFile" property alias) on the IPublishedContent item
+ ///
+ ///
+ /// The IPublishedContent item.
+ ///
+ ///
+ /// The crop alias e.g. thumbnail
+ ///
+ ///
+ /// The ImageProcessor.Web Url.
+ ///
+ public static string GetCropUrl(this IPublishedContent mediaItem, string cropAlias, IImageUrlGenerator imageUrlGenerator)
+ {
+ return mediaItem.GetCropUrl(imageUrlGenerator, cropAlias: cropAlias, useCropDimensions: true);
+ }
+
+ ///
+ /// Gets the ImageProcessor Url by the crop alias using the specified property containing the image cropper Json data on the IPublishedContent item.
+ ///
+ ///
+ /// The IPublishedContent item.
+ ///
+ ///
+ /// The property alias of the property containing the Json data e.g. umbracoFile
+ ///
+ ///
+ /// The crop alias e.g. thumbnail
+ ///
+ ///
+ /// The ImageProcessor.Web Url.
+ ///
+ public static string GetCropUrl(this IPublishedContent mediaItem, string propertyAlias, string cropAlias, IImageUrlGenerator imageUrlGenerator)
+ {
+ return mediaItem.GetCropUrl(imageUrlGenerator, propertyAlias: propertyAlias, cropAlias: cropAlias, useCropDimensions: true);
+ }
+
+ ///
+ /// Gets the ImageProcessor Url from the IPublishedContent item.
+ ///
+ ///
+ /// The IPublishedContent item.
+ ///
+ ///
+ /// The width of the output image.
+ ///
+ ///
+ /// The height of the output image.
+ ///
+ ///
+ /// Property alias of the property containing the Json data.
+ ///
+ ///
+ /// The crop alias.
+ ///
+ ///
+ /// Quality percentage of the output image.
+ ///
+ ///
+ /// The image crop mode.
+ ///
+ ///
+ /// The image crop anchor.
+ ///
+ ///
+ /// Use focal point, to generate an output image using the focal point instead of the predefined crop
+ ///
+ ///
+ /// Use crop dimensions to have the output image sized according to the predefined crop sizes, this will override the width and height parameters.
+ ///
+ ///
+ /// Add a serialized date of the last edit of the item to ensure client cache refresh when updated
+ ///
+ ///
+ /// These are any query string parameters (formatted as query strings) that ImageProcessor supports. For example:
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Use a dimension as a ratio
+ ///
+ ///
+ /// If the image should be upscaled to requested dimensions
+ ///
+ ///
+ /// The .
+ ///
+ public static string GetCropUrl(
+ this IPublishedContent mediaItem,
+ IImageUrlGenerator imageUrlGenerator,
+ int? width = null,
+ int? height = null,
+ string propertyAlias = Constants.Conventions.Media.File,
+ string cropAlias = null,
+ int? quality = null,
+ ImageCropMode? imageCropMode = null,
+ ImageCropAnchor? imageCropAnchor = null,
+ bool preferFocalPoint = false,
+ bool useCropDimensions = false,
+ bool cacheBuster = true,
+ string furtherOptions = null,
+ ImageCropRatioMode? ratioMode = null,
+ bool upScale = true)
+ {
+ if (mediaItem == null) throw new ArgumentNullException("mediaItem");
+
+ var cacheBusterValue = cacheBuster ? mediaItem.UpdateDate.ToFileTimeUtc().ToString(CultureInfo.InvariantCulture) : null;
+
+ if (mediaItem.HasProperty(propertyAlias) == false || mediaItem.HasValue(propertyAlias) == false)
+ return string.Empty;
+
+ var mediaItemUrl = mediaItem.MediaUrl(propertyAlias: propertyAlias);
+
+ //get the default obj from the value converter
+ var cropperValue = mediaItem.Value(propertyAlias);
+
+ //is it strongly typed?
+ var stronglyTyped = cropperValue as ImageCropperValue;
+ if (stronglyTyped != null)
+ {
+ return GetCropUrl(
+ mediaItemUrl, imageUrlGenerator, stronglyTyped, width, height, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions,
+ cacheBusterValue, furtherOptions, ratioMode, upScale);
+ }
+
+ //this shouldn't be the case but we'll check
+ var jobj = cropperValue as JObject;
+ if (jobj != null)
+ {
+ stronglyTyped = jobj.ToObject();
+ return GetCropUrl(
+ mediaItemUrl, imageUrlGenerator, stronglyTyped, width, height, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions,
+ cacheBusterValue, furtherOptions, ratioMode, upScale);
+ }
+
+ //it's a single string
+ return GetCropUrl(
+ mediaItemUrl, imageUrlGenerator, width, height, mediaItemUrl, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions,
+ cacheBusterValue, furtherOptions, ratioMode, upScale);
+ }
+
+ ///
+ /// Gets the ImageProcessor Url from the image path.
+ ///
+ ///
+ /// The image url.
+ ///
+ ///
+ /// The width of the output image.
+ ///
+ ///
+ /// The height of the output image.
+ ///
+ ///
+ /// The Json data from the Umbraco Core Image Cropper property editor
+ ///
+ ///
+ /// The crop alias.
+ ///
+ ///
+ /// Quality percentage of the output image.
+ ///
+ ///
+ /// The image crop mode.
+ ///
+ ///
+ /// The image crop anchor.
+ ///
+ ///
+ /// Use focal point to generate an output image using the focal point instead of the predefined crop if there is one
+ ///
+ ///
+ /// Use crop dimensions to have the output image sized according to the predefined crop sizes, this will override the width and height parameters
+ ///
+ ///
+ /// Add a serialized date of the last edit of the item to ensure client cache refresh when updated
+ ///
+ ///
+ /// These are any query string parameters (formatted as query strings) that ImageProcessor supports. For example:
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Use a dimension as a ratio
+ ///
+ ///
+ /// If the image should be upscaled to requested dimensions
+ ///
+ ///
+ /// The .
+ ///
+ public static string GetCropUrl(
+ this string imageUrl,
+ IImageUrlGenerator imageUrlGenerator,
+ int? width = null,
+ int? height = null,
+ string imageCropperValue = null,
+ string cropAlias = null,
+ int? quality = null,
+ ImageCropMode? imageCropMode = null,
+ ImageCropAnchor? imageCropAnchor = null,
+ bool preferFocalPoint = false,
+ bool useCropDimensions = false,
+ string cacheBusterValue = null,
+ string furtherOptions = null,
+ ImageCropRatioMode? ratioMode = null,
+ bool upScale = true)
+ {
+ if (string.IsNullOrEmpty(imageUrl)) return string.Empty;
+
+ ImageCropperValue cropDataSet = null;
+ if (string.IsNullOrEmpty(imageCropperValue) == false && imageCropperValue.DetectIsJson() && (imageCropMode == ImageCropMode.Crop || imageCropMode == null))
+ {
+ cropDataSet = imageCropperValue.DeserializeImageCropperValue();
+ }
+ return GetCropUrl(
+ imageUrl, imageUrlGenerator, cropDataSet, width, height, cropAlias, quality, imageCropMode,
+ imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode, upScale);
+ }
+
+ ///
+ /// Gets the ImageProcessor Url from the image path.
+ ///
+ ///
+ /// The image url.
+ ///
+ ///
+ /// The generator that will process all the options and the image URL to return a full image urls with all processing options appended
+ ///
+ ///
+ ///
+ /// The width of the output image.
+ ///
+ ///
+ /// The height of the output image.
+ ///
+ ///
+ /// The crop alias.
+ ///
+ ///
+ /// Quality percentage of the output image.
+ ///
+ ///
+ /// The image crop mode.
+ ///
+ ///
+ /// The image crop anchor.
+ ///
+ ///
+ /// Use focal point to generate an output image using the focal point instead of the predefined crop if there is one
+ ///
+ ///
+ /// Use crop dimensions to have the output image sized according to the predefined crop sizes, this will override the width and height parameters
+ ///
+ ///
+ /// Add a serialized date of the last edit of the item to ensure client cache refresh when updated
+ ///
+ ///
+ /// These are any query string parameters (formatted as query strings) that ImageProcessor supports. For example:
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Use a dimension as a ratio
+ ///
+ ///
+ /// If the image should be upscaled to requested dimensions
+ ///
+ ///
+ /// The .
+ ///
+ public static string GetCropUrl(
+ this string imageUrl,
+ IImageUrlGenerator imageUrlGenerator,
+ ImageCropperValue cropDataSet,
+ int? width = null,
+ int? height = null,
+ string cropAlias = null,
+ int? quality = null,
+ ImageCropMode? imageCropMode = null,
+ ImageCropAnchor? imageCropAnchor = null,
+ bool preferFocalPoint = false,
+ bool useCropDimensions = false,
+ string cacheBusterValue = null,
+ string furtherOptions = null,
+ ImageCropRatioMode? ratioMode = null,
+ bool upScale = true,
+ string animationProcessMode = null)
+ {
+ if (string.IsNullOrEmpty(imageUrl)) return string.Empty;
+
+ ImageUrlGenerationOptions options;
+
+ if (cropDataSet != null && (imageCropMode == ImageCropMode.Crop || imageCropMode == null))
+ {
+ var crop = cropDataSet.GetCrop(cropAlias);
+
+ // if a crop was specified, but not found, return null
+ if (crop == null && !string.IsNullOrWhiteSpace(cropAlias))
+ return null;
+
+ options = cropDataSet.GetCropBaseOptions(imageUrl, crop, string.IsNullOrWhiteSpace(cropAlias), preferFocalPoint);
+
+ if (crop != null & useCropDimensions)
+ {
+ width = crop.Width;
+ height = crop.Height;
+ }
+
+ // If a predefined crop has been specified & there are no coordinates & no ratio mode, but a width parameter has been passed we can get the crop ratio for the height
+ if (crop != null && string.IsNullOrEmpty(cropAlias) == false && crop.Coordinates == null && ratioMode == null && width != null && height == null)
+ {
+ options.HeightRatio = (decimal)crop.Height / crop.Width;
+ }
+
+ // If a predefined crop has been specified & there are no coordinates & no ratio mode, but a height parameter has been passed we can get the crop ratio for the width
+ if (crop != null && string.IsNullOrEmpty(cropAlias) == false && crop.Coordinates == null && ratioMode == null && width == null && height != null)
+ {
+ options.WidthRatio = (decimal)crop.Width / crop.Height;
+ }
+ }
+ else
+ {
+ options = new ImageUrlGenerationOptions (imageUrl)
+ {
+ ImageCropMode = (imageCropMode ?? ImageCropMode.Pad).ToString().ToLowerInvariant(),
+ ImageCropAnchor = imageCropAnchor?.ToString().ToLowerInvariant()
+ };
+ }
+
+ options.Quality = quality;
+ options.Width = ratioMode != null && ratioMode.Value == ImageCropRatioMode.Width ? null : width;
+ options.Height = ratioMode != null && ratioMode.Value == ImageCropRatioMode.Height ? null : height;
+ options.AnimationProcessMode = animationProcessMode;
+
+ if (ratioMode == ImageCropRatioMode.Width && height != null)
+ {
+ // if only height specified then assume a square
+ if (width == null) width = height;
+ options.WidthRatio = (decimal)width / (decimal)height;
+ }
+
+ if (ratioMode == ImageCropRatioMode.Height && width != null)
+ {
+ // if only width specified then assume a square
+ if (height == null) height = width;
+ options.HeightRatio = (decimal)height / (decimal)width;
+ }
+
+ options.UpScale = upScale;
+ options.FurtherOptions = furtherOptions;
+ options.CacheBusterValue = cacheBusterValue;
+
+ return imageUrlGenerator.GetImageUrl(options);
+ }
+ }
+}
diff --git a/src/Umbraco.Web/ImageCropperTemplateExtensions.cs b/src/Umbraco.Web/ImageCropperTemplateExtensions.cs
index 440083a11f..3c10aba227 100644
--- a/src/Umbraco.Web/ImageCropperTemplateExtensions.cs
+++ b/src/Umbraco.Web/ImageCropperTemplateExtensions.cs
@@ -1,14 +1,9 @@
using System;
-using Newtonsoft.Json.Linq;
using System.Globalization;
-using System.Text;
using Newtonsoft.Json;
using Umbraco.Core;
using Umbraco.Web.Composing;
-using Umbraco.Core.Models;
-using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors.ValueConverters;
-using Umbraco.Web.Models;
namespace Umbraco.Web
{
@@ -17,419 +12,6 @@ namespace Umbraco.Web
///
public static class ImageCropperTemplateExtensions
{
- ///
- /// Gets the ImageProcessor Url by the crop alias (from the "umbracoFile" property alias) on the IPublishedContent item
- ///
- ///
- /// The IPublishedContent item.
- ///
- ///
- /// The crop alias e.g. thumbnail
- ///
- ///
- /// The ImageProcessor.Web Url.
- ///
- public static string GetCropUrl(this IPublishedContent mediaItem, string cropAlias)
- {
- return mediaItem.GetCropUrl(cropAlias: cropAlias, useCropDimensions: true);
- }
-
- ///
- /// Gets the ImageProcessor Url by the crop alias using the specified property containing the image cropper Json data on the IPublishedContent item.
- ///
- ///
- /// The IPublishedContent item.
- ///
- ///
- /// The property alias of the property containing the Json data e.g. umbracoFile
- ///
- ///
- /// The crop alias e.g. thumbnail
- ///
- ///
- /// The ImageProcessor.Web Url.
- ///
- public static string GetCropUrl(this IPublishedContent mediaItem, string propertyAlias, string cropAlias)
- {
- return mediaItem.GetCropUrl(propertyAlias: propertyAlias, cropAlias: cropAlias, useCropDimensions: true);
- }
-
- ///
- /// Gets the ImageProcessor Url from the IPublishedContent item.
- ///
- ///
- /// The IPublishedContent item.
- ///
- ///
- /// The width of the output image.
- ///
- ///
- /// The height of the output image.
- ///
- ///
- /// Property alias of the property containing the Json data.
- ///
- ///
- /// The crop alias.
- ///
- ///
- /// Quality percentage of the output image.
- ///
- ///
- /// The image crop mode.
- ///
- ///
- /// The image crop anchor.
- ///
- ///
- /// Use focal point, to generate an output image using the focal point instead of the predefined crop
- ///
- ///
- /// Use crop dimensions to have the output image sized according to the predefined crop sizes, this will override the width and height parameters.
- ///
- ///
- /// Add a serialized date of the last edit of the item to ensure client cache refresh when updated
- ///
- ///
- /// These are any query string parameters (formatted as query strings) that ImageProcessor supports. For example:
- ///
- ///
- ///
- ///
- ///
- /// Use a dimension as a ratio
- ///
- ///
- /// If the image should be upscaled to requested dimensions
- ///
- ///
- /// The .
- ///
- public static string GetCropUrl(
- this IPublishedContent mediaItem,
- int? width = null,
- int? height = null,
- string propertyAlias = Constants.Conventions.Media.File,
- string cropAlias = null,
- int? quality = null,
- ImageCropMode? imageCropMode = null,
- ImageCropAnchor? imageCropAnchor = null,
- bool preferFocalPoint = false,
- bool useCropDimensions = false,
- bool cacheBuster = true,
- string furtherOptions = null,
- ImageCropRatioMode? ratioMode = null,
- bool upScale = true)
- {
- if (mediaItem == null) throw new ArgumentNullException("mediaItem");
-
- var cacheBusterValue = cacheBuster ? mediaItem.UpdateDate.ToFileTimeUtc().ToString(CultureInfo.InvariantCulture) : null;
-
- if (mediaItem.HasProperty(propertyAlias) == false || mediaItem.HasValue(propertyAlias) == false)
- return string.Empty;
-
- var mediaItemUrl = mediaItem.MediaUrl(propertyAlias: propertyAlias);
-
- //get the default obj from the value converter
- var cropperValue = mediaItem.Value(propertyAlias);
-
- //is it strongly typed?
- var stronglyTyped = cropperValue as ImageCropperValue;
- if (stronglyTyped != null)
- {
- return GetCropUrl(
- mediaItemUrl, stronglyTyped, width, height, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions,
- cacheBusterValue, furtherOptions, ratioMode, upScale);
- }
-
- //this shouldn't be the case but we'll check
- var jobj = cropperValue as JObject;
- if (jobj != null)
- {
- stronglyTyped = jobj.ToObject();
- return GetCropUrl(
- mediaItemUrl, stronglyTyped, width, height, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions,
- cacheBusterValue, furtherOptions, ratioMode, upScale);
- }
-
- //it's a single string
- return GetCropUrl(
- mediaItemUrl, width, height, mediaItemUrl, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions,
- cacheBusterValue, furtherOptions, ratioMode, upScale);
- }
-
- ///
- /// Gets the ImageProcessor Url from the image path.
- ///
- ///
- /// The image url.
- ///
- ///
- /// The width of the output image.
- ///
- ///
- /// The height of the output image.
- ///
- ///
- /// The Json data from the Umbraco Core Image Cropper property editor
- ///
- ///
- /// The crop alias.
- ///
- ///
- /// Quality percentage of the output image.
- ///
- ///
- /// The image crop mode.
- ///
- ///
- /// The image crop anchor.
- ///
- ///
- /// Use focal point to generate an output image using the focal point instead of the predefined crop if there is one
- ///
- ///
- /// Use crop dimensions to have the output image sized according to the predefined crop sizes, this will override the width and height parameters
- ///
- ///
- /// Add a serialized date of the last edit of the item to ensure client cache refresh when updated
- ///
- ///
- /// These are any query string parameters (formatted as query strings) that ImageProcessor supports. For example:
- ///
- ///
- ///
- ///
- ///
- /// Use a dimension as a ratio
- ///
- ///
- /// If the image should be upscaled to requested dimensions
- ///
- ///
- /// The .
- ///
- public static string GetCropUrl(
- this string imageUrl,
- int? width = null,
- int? height = null,
- string imageCropperValue = null,
- string cropAlias = null,
- int? quality = null,
- ImageCropMode? imageCropMode = null,
- ImageCropAnchor? imageCropAnchor = null,
- bool preferFocalPoint = false,
- bool useCropDimensions = false,
- string cacheBusterValue = null,
- string furtherOptions = null,
- ImageCropRatioMode? ratioMode = null,
- bool upScale = true)
- {
- if (string.IsNullOrEmpty(imageUrl)) return string.Empty;
-
- ImageCropperValue cropDataSet = null;
- if (string.IsNullOrEmpty(imageCropperValue) == false && imageCropperValue.DetectIsJson() && (imageCropMode == ImageCropMode.Crop || imageCropMode == null))
- {
- cropDataSet = imageCropperValue.DeserializeImageCropperValue();
- }
- return GetCropUrl(
- imageUrl, cropDataSet, width, height, cropAlias, quality, imageCropMode,
- imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode, upScale);
- }
-
- ///
- /// Gets the ImageProcessor Url from the image path.
- ///
- ///
- /// The image url.
- ///
- ///
- ///
- /// The width of the output image.
- ///
- ///
- /// The height of the output image.
- ///
- ///
- /// The crop alias.
- ///
- ///
- /// Quality percentage of the output image.
- ///
- ///
- /// The image crop mode.
- ///
- ///
- /// The image crop anchor.
- ///
- ///
- /// Use focal point to generate an output image using the focal point instead of the predefined crop if there is one
- ///
- ///
- /// Use crop dimensions to have the output image sized according to the predefined crop sizes, this will override the width and height parameters
- ///
- ///
- /// Add a serialized date of the last edit of the item to ensure client cache refresh when updated
- ///
- ///
- /// These are any query string parameters (formatted as query strings) that ImageProcessor supports. For example:
- ///
- ///
- ///
- ///
- ///
- /// Use a dimension as a ratio
- ///
- ///
- /// If the image should be upscaled to requested dimensions
- ///
- ///
- /// The .
- ///
- public static string GetCropUrl(
- this string imageUrl,
- ImageCropperValue cropDataSet,
- int? width = null,
- int? height = null,
- string cropAlias = null,
- int? quality = null,
- ImageCropMode? imageCropMode = null,
- ImageCropAnchor? imageCropAnchor = null,
- bool preferFocalPoint = false,
- bool useCropDimensions = false,
- string cacheBusterValue = null,
- string furtherOptions = null,
- ImageCropRatioMode? ratioMode = null,
- bool upScale = true)
- {
- if (string.IsNullOrEmpty(imageUrl) == false)
- {
- var imageProcessorUrl = new StringBuilder();
-
- if (cropDataSet != null && (imageCropMode == ImageCropMode.Crop || imageCropMode == null))
- {
- var crop = cropDataSet.GetCrop(cropAlias);
-
- // if a crop was specified, but not found, return null
- if (crop == null && !string.IsNullOrWhiteSpace(cropAlias))
- return null;
-
- imageProcessorUrl.Append(imageUrl);
- cropDataSet.AppendCropBaseUrl(imageProcessorUrl, crop, string.IsNullOrWhiteSpace(cropAlias), preferFocalPoint);
-
- if (crop != null & useCropDimensions)
- {
- width = crop.Width;
- height = crop.Height;
- }
-
- // If a predefined crop has been specified & there are no coordinates & no ratio mode, but a width parameter has been passed we can get the crop ratio for the height
- if (crop != null && string.IsNullOrEmpty(cropAlias) == false && crop.Coordinates == null && ratioMode == null && width != null && height == null)
- {
- var heightRatio = (decimal)crop.Height / (decimal)crop.Width;
- imageProcessorUrl.Append("&heightratio=" + heightRatio.ToString(CultureInfo.InvariantCulture));
- }
-
- // If a predefined crop has been specified & there are no coordinates & no ratio mode, but a height parameter has been passed we can get the crop ratio for the width
- if (crop != null && string.IsNullOrEmpty(cropAlias) == false && crop.Coordinates == null && ratioMode == null && width == null && height != null)
- {
- var widthRatio = (decimal)crop.Width / (decimal)crop.Height;
- imageProcessorUrl.Append("&widthratio=" + widthRatio.ToString(CultureInfo.InvariantCulture));
- }
- }
- else
- {
- imageProcessorUrl.Append(imageUrl);
-
- if (imageCropMode == null)
- {
- imageCropMode = ImageCropMode.Pad;
- }
-
- imageProcessorUrl.Append("?mode=" + imageCropMode.ToString().ToLower());
-
- if (imageCropAnchor != null)
- {
- imageProcessorUrl.Append("&anchor=" + imageCropAnchor.ToString().ToLower());
- }
- }
-
- var hasFormat = furtherOptions != null && furtherOptions.InvariantContains("&format=");
-
- //Only put quality here, if we don't have a format specified.
- //Otherwise we need to put quality at the end to avoid it being overridden by the format.
- if (quality != null && hasFormat == false)
- {
- imageProcessorUrl.Append("&quality=" + quality);
- }
-
- if (width != null && ratioMode != ImageCropRatioMode.Width)
- {
- imageProcessorUrl.Append("&width=" + width);
- }
-
- if (height != null && ratioMode != ImageCropRatioMode.Height)
- {
- imageProcessorUrl.Append("&height=" + height);
- }
-
- if (ratioMode == ImageCropRatioMode.Width && height != null)
- {
- // if only height specified then assume a square
- if (width == null)
- {
- width = height;
- }
-
- var widthRatio = (decimal)width / (decimal)height;
- imageProcessorUrl.Append("&widthratio=" + widthRatio.ToString(CultureInfo.InvariantCulture));
- }
-
- if (ratioMode == ImageCropRatioMode.Height && width != null)
- {
- // if only width specified then assume a square
- if (height == null)
- {
- height = width;
- }
-
- var heightRatio = (decimal)height / (decimal)width;
- imageProcessorUrl.Append("&heightratio=" + heightRatio.ToString(CultureInfo.InvariantCulture));
- }
-
- if (upScale == false)
- {
- imageProcessorUrl.Append("&upscale=false");
- }
-
- if (furtherOptions != null)
- {
- imageProcessorUrl.Append(furtherOptions);
- }
-
- //If furtherOptions contains a format, we need to put the quality after the format.
- if (quality != null && hasFormat)
- {
- imageProcessorUrl.Append("&quality=" + quality);
- }
-
- if (cacheBusterValue != null)
- {
- imageProcessorUrl.Append("&rnd=").Append(cacheBusterValue);
- }
-
- return imageProcessorUrl.ToString();
- }
-
- return string.Empty;
- }
-
internal static ImageCropperValue DeserializeImageCropperValue(this string json)
{
var imageCrops = new ImageCropperValue();
diff --git a/src/Umbraco.Web/Models/ImageProcessorImageUrlGenerator.cs b/src/Umbraco.Web/Models/ImageProcessorImageUrlGenerator.cs
new file mode 100644
index 0000000000..e471e9aa4a
--- /dev/null
+++ b/src/Umbraco.Web/Models/ImageProcessorImageUrlGenerator.cs
@@ -0,0 +1,64 @@
+using System.Globalization;
+using System.Text;
+using Umbraco.Core;
+using Umbraco.Core.Models;
+
+namespace Umbraco.Web.Models
+{
+ internal class ImageProcessorImageUrlGenerator : IImageUrlGenerator
+ {
+ public string GetImageUrl(ImageUrlGenerationOptions options)
+ {
+ if (options == null) return null;
+
+ var imageProcessorUrl = new StringBuilder(options.ImageUrl ?? string.Empty);
+
+ if (options.FocalPoint != null) AppendFocalPoint(imageProcessorUrl, options);
+ else if (options.Crop != null) AppendCrop(imageProcessorUrl, options);
+ else if (options.DefaultCrop) imageProcessorUrl.Append("?anchor=center&mode=crop");
+ else
+ {
+ imageProcessorUrl.Append("?mode=").Append((options.ImageCropMode ?? "crop").ToLower());
+
+ if (options.ImageCropAnchor != null) imageProcessorUrl.Append("&anchor=").Append(options.ImageCropAnchor.ToLower());
+ }
+
+ var hasFormat = options.FurtherOptions != null && options.FurtherOptions.InvariantContains("&format=");
+
+ //Only put quality here, if we don't have a format specified.
+ //Otherwise we need to put quality at the end to avoid it being overridden by the format.
+ if (options.Quality != null && hasFormat == false) imageProcessorUrl.Append("&quality=").Append(options.Quality);
+ if (options.HeightRatio != null) imageProcessorUrl.Append("&heightratio=").Append(options.HeightRatio.Value.ToString(CultureInfo.InvariantCulture));
+ if (options.WidthRatio != null) imageProcessorUrl.Append("&widthratio=").Append(options.WidthRatio.Value.ToString(CultureInfo.InvariantCulture));
+ if (options.Width != null) imageProcessorUrl.Append("&width=").Append(options.Width);
+ if (options.Height != null) imageProcessorUrl.Append("&height=").Append(options.Height);
+ if (options.UpScale == false) imageProcessorUrl.Append("&upscale=false");
+ if (options.AnimationProcessMode != null) imageProcessorUrl.Append("&animationprocessmode=").Append(options.AnimationProcessMode);
+ if (options.FurtherOptions != null) imageProcessorUrl.Append(options.FurtherOptions);
+
+ //If furtherOptions contains a format, we need to put the quality after the format.
+ if (options.Quality != null && hasFormat) imageProcessorUrl.Append("&quality=").Append(options.Quality);
+ if (options.CacheBusterValue != null) imageProcessorUrl.Append("&rnd=").Append(options.CacheBusterValue);
+
+ return imageProcessorUrl.ToString();
+ }
+
+ private void AppendFocalPoint(StringBuilder imageProcessorUrl, ImageUrlGenerationOptions options)
+ {
+ imageProcessorUrl.Append("?center=");
+ imageProcessorUrl.Append(options.FocalPoint.Top.ToString(CultureInfo.InvariantCulture)).Append(",");
+ imageProcessorUrl.Append(options.FocalPoint.Left.ToString(CultureInfo.InvariantCulture));
+ imageProcessorUrl.Append("&mode=crop");
+ }
+
+ private void AppendCrop(StringBuilder imageProcessorUrl, ImageUrlGenerationOptions options)
+ {
+ imageProcessorUrl.Append("?crop=");
+ imageProcessorUrl.Append(options.Crop.X1.ToString(CultureInfo.InvariantCulture)).Append(",");
+ imageProcessorUrl.Append(options.Crop.Y1.ToString(CultureInfo.InvariantCulture)).Append(",");
+ imageProcessorUrl.Append(options.Crop.X2.ToString(CultureInfo.InvariantCulture)).Append(",");
+ imageProcessorUrl.Append(options.Crop.Y2.ToString(CultureInfo.InvariantCulture));
+ imageProcessorUrl.Append("&cropmode=percentage");
+ }
+ }
+}
diff --git a/src/Umbraco.Web/Models/Mapping/UserMapDefinition.cs b/src/Umbraco.Web/Models/Mapping/UserMapDefinition.cs
index 8844b848bc..556b15d72b 100644
--- a/src/Umbraco.Web/Models/Mapping/UserMapDefinition.cs
+++ b/src/Umbraco.Web/Models/Mapping/UserMapDefinition.cs
@@ -31,9 +31,11 @@ namespace Umbraco.Web.Models.Mapping
private readonly IGlobalSettings _globalSettings;
private readonly IMediaFileSystem _mediaFileSystem;
private readonly IShortStringHelper _shortStringHelper;
+ private readonly IImageUrlGenerator _imageUrlGenerator;
public UserMapDefinition(ILocalizedTextService textService, IUserService userService, IEntityService entityService, ISectionService sectionService,
- AppCaches appCaches, ActionCollection actions, IGlobalSettings globalSettings, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper)
+ AppCaches appCaches, ActionCollection actions, IGlobalSettings globalSettings, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper,
+ IImageUrlGenerator imageUrlGenerator)
{
_sectionService = sectionService;
_entityService = entityService;
@@ -44,6 +46,7 @@ namespace Umbraco.Web.Models.Mapping
_globalSettings = globalSettings;
_mediaFileSystem = mediaFileSystem;
_shortStringHelper = shortStringHelper;
+ _imageUrlGenerator = imageUrlGenerator;
}
public void DefineMaps(UmbracoMapper mapper)
@@ -279,7 +282,7 @@ namespace Umbraco.Web.Models.Mapping
private void Map(IUser source, UserDisplay target, MapperContext context)
{
target.AvailableCultures = _textService.GetSupportedCultures().ToDictionary(x => x.Name, x => x.DisplayName);
- target.Avatars = source.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileSystem);
+ target.Avatars = source.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileSystem, _imageUrlGenerator);
target.CalculatedStartContentIds = GetStartNodes(source.CalculateContentStartNodeIds(_entityService), UmbracoObjectTypes.Document, "content/contentRoot", context);
target.CalculatedStartMediaIds = GetStartNodes(source.CalculateMediaStartNodeIds(_entityService), UmbracoObjectTypes.Media, "media/mediaRoot", context);
target.CreateDate = source.CreateDate;
@@ -310,7 +313,7 @@ namespace Umbraco.Web.Models.Mapping
//Loading in the user avatar's requires an external request if they don't have a local file avatar, this means that initial load of paging may incur a cost
//Alternatively, if this is annoying the back office UI would need to be updated to request the avatars for the list of users separately so it doesn't look
//like the load time is waiting.
- target.Avatars = source.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileSystem);
+ target.Avatars = source.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileSystem, _imageUrlGenerator);
target.Culture = source.GetUserCulture(_textService, _globalSettings).ToString();
target.Email = source.Email;
target.EmailHash = source.Email.ToLowerInvariant().Trim().GenerateHash();
@@ -329,7 +332,7 @@ namespace Umbraco.Web.Models.Mapping
private void Map(IUser source, UserDetail target, MapperContext context)
{
target.AllowedSections = source.AllowedSections;
- target.Avatars = source.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileSystem);
+ target.Avatars = source.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileSystem, _imageUrlGenerator);
target.Culture = source.GetUserCulture(_textService, _globalSettings).ToString();
target.Email = source.Email;
target.EmailHash = source.Email.ToLowerInvariant().Trim().GenerateHash();
diff --git a/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs
index 161a73d775..7ab2ed2a36 100644
--- a/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs
+++ b/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs
@@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
+using Umbraco.Core.Composing;
using Umbraco.Web.Composing;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
@@ -38,6 +39,7 @@ namespace Umbraco.Web.PropertyEditors
private readonly HtmlImageSourceParser _imageSourceParser;
private readonly RichTextEditorPastedImages _pastedImages;
private readonly HtmlLocalLinkParser _localLinkParser;
+ private readonly IImageUrlGenerator _imageUrlGenerator;
public GridPropertyEditor(
ILogger logger,
@@ -51,7 +53,8 @@ namespace Umbraco.Web.PropertyEditors
RichTextEditorPastedImages pastedImages,
HtmlLocalLinkParser localLinkParser,
IIOHelper ioHelper,
- IShortStringHelper shortStringHelper)
+ IShortStringHelper shortStringHelper,
+ IImageUrlGenerator imageUrlGenerator)
: base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper)
{
_umbracoContextAccessor = umbracoContextAccessor;
@@ -64,6 +67,7 @@ namespace Umbraco.Web.PropertyEditors
_imageSourceParser = imageSourceParser;
_pastedImages = pastedImages;
_localLinkParser = localLinkParser;
+ _imageUrlGenerator = imageUrlGenerator;
}
public override IPropertyIndexValueFactory PropertyIndexValueFactory => new GridPropertyIndexValueFactory();
@@ -72,7 +76,7 @@ namespace Umbraco.Web.PropertyEditors
/// Overridden to ensure that the value is validated
///
///
- protected override IDataValueEditor CreateValueEditor() => new GridPropertyValueEditor(Attribute, _mediaService, _contentTypeBaseServiceProvider, _umbracoContextAccessor, _logger, DataTypeService, LocalizationService, LocalizedTextService, _imageSourceParser, _pastedImages, _localLinkParser, ShortStringHelper);
+ protected override IDataValueEditor CreateValueEditor() => new GridPropertyValueEditor(Attribute, _mediaService, _contentTypeBaseServiceProvider, _umbracoContextAccessor, _logger, DataTypeService, LocalizationService, LocalizedTextService, _imageSourceParser, _pastedImages, _localLinkParser, ShortStringHelper, _imageUrlGenerator);
protected override IConfigurationEditor CreateConfigurationEditor() => new GridConfigurationEditor(_ioHelper);
@@ -83,6 +87,7 @@ namespace Umbraco.Web.PropertyEditors
private readonly RichTextEditorPastedImages _pastedImages;
private readonly RichTextPropertyEditor.RichTextPropertyValueEditor _richTextPropertyValueEditor;
private readonly MediaPickerPropertyEditor.MediaPickerPropertyValueEditor _mediaPickerPropertyValueEditor;
+ private readonly IImageUrlGenerator _imageUrlGenerator;
public GridPropertyValueEditor(
DataEditorAttribute attribute,
@@ -96,14 +101,16 @@ namespace Umbraco.Web.PropertyEditors
HtmlImageSourceParser imageSourceParser,
RichTextEditorPastedImages pastedImages,
HtmlLocalLinkParser localLinkParser,
- IShortStringHelper shortStringHelper)
+ IShortStringHelper shortStringHelper,
+ IImageUrlGenerator imageUrlGenerator)
: base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute)
{
_umbracoContextAccessor = umbracoContextAccessor;
_imageSourceParser = imageSourceParser;
_pastedImages = pastedImages;
- _richTextPropertyValueEditor = new RichTextPropertyEditor.RichTextPropertyValueEditor(attribute, umbracoContextAccessor, dataTypeService, localizationService, localizedTextService, shortStringHelper, imageSourceParser, localLinkParser, pastedImages);
+ _richTextPropertyValueEditor = new RichTextPropertyEditor.RichTextPropertyValueEditor(attribute, umbracoContextAccessor, dataTypeService, localizationService, localizedTextService, shortStringHelper, imageSourceParser, localLinkParser, pastedImages, imageUrlGenerator);
_mediaPickerPropertyValueEditor = new MediaPickerPropertyEditor.MediaPickerPropertyValueEditor(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute);
+ _imageUrlGenerator = imageUrlGenerator;
}
///
@@ -138,7 +145,7 @@ namespace Umbraco.Web.PropertyEditors
// Parse the HTML
var html = rte.Value?.ToString();
- var parseAndSavedTempImages = _pastedImages.FindAndPersistPastedTempImages(html, mediaParentId, userId);
+ var parseAndSavedTempImages = _pastedImages.FindAndPersistPastedTempImages(html, mediaParentId, userId, _imageUrlGenerator);
var editorValueWithMediaUrlsRemoved = _imageSourceParser.RemoveImageSources(parseAndSavedTempImages);
rte.Value = editorValueWithMediaUrlsRemoved;
diff --git a/src/Umbraco.Web/PropertyEditors/RichTextEditorPastedImages.cs b/src/Umbraco.Web/PropertyEditors/RichTextEditorPastedImages.cs
index 76e9d9742f..4b956bbe5b 100644
--- a/src/Umbraco.Web/PropertyEditors/RichTextEditorPastedImages.cs
+++ b/src/Umbraco.Web/PropertyEditors/RichTextEditorPastedImages.cs
@@ -43,7 +43,7 @@ namespace Umbraco.Web.PropertyEditors
///
///
///
- internal string FindAndPersistPastedTempImages(string html, Guid mediaParentFolder, int userId)
+ internal string FindAndPersistPastedTempImages(string html, Guid mediaParentFolder, int userId, IImageUrlGenerator imageUrlGenerator)
{
// Find all img's that has data-tmpimg attribute
// Use HTML Agility Pack - https://html-agility-pack.net
@@ -116,7 +116,7 @@ namespace Umbraco.Web.PropertyEditors
if (width != int.MinValue && height != int.MinValue)
{
- location = $"{location}?width={width}&height={height}&mode=max";
+ location = imageUrlGenerator.GetImageUrl(new ImageUrlGenerationOptions(location) { ImageCropMode = "max", Width = width, Height = height });
}
img.SetAttributeValue("src", location);
diff --git a/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs
index 7cf9e3a6d9..da3342a682 100644
--- a/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs
+++ b/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs
@@ -33,6 +33,7 @@ namespace Umbraco.Web.PropertyEditors
private readonly HtmlLocalLinkParser _localLinkParser;
private readonly RichTextEditorPastedImages _pastedImages;
private readonly IIOHelper _ioHelper;
+ private readonly IImageUrlGenerator _imageUrlGenerator;
///
/// The constructor will setup the property editor based on the attribute if one is found
@@ -49,7 +50,8 @@ namespace Umbraco.Web.PropertyEditors
RichTextEditorPastedImages pastedImages,
IShortStringHelper shortStringHelper,
IIOHelper ioHelper,
- ILocalizedTextService localizedTextService)
+ ILocalizedTextService localizedTextService,
+ IImageUrlGenerator imageUrlGenerator)
: base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper)
{
_umbracoContextAccessor = umbracoContextAccessor;
@@ -57,13 +59,14 @@ namespace Umbraco.Web.PropertyEditors
_localLinkParser = localLinkParser;
_pastedImages = pastedImages;
_ioHelper = ioHelper;
+ _imageUrlGenerator = imageUrlGenerator;
}
///
/// Create a custom value editor
///
///
- protected override IDataValueEditor CreateValueEditor() => new RichTextPropertyValueEditor(Attribute, _umbracoContextAccessor, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, _imageSourceParser, _localLinkParser, _pastedImages);
+ protected override IDataValueEditor CreateValueEditor() => new RichTextPropertyValueEditor(Attribute, _umbracoContextAccessor, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, _imageSourceParser, _localLinkParser, _pastedImages, _imageUrlGenerator);
protected override IConfigurationEditor CreateConfigurationEditor() => new RichTextConfigurationEditor(_ioHelper);
@@ -78,6 +81,7 @@ namespace Umbraco.Web.PropertyEditors
private readonly HtmlImageSourceParser _imageSourceParser;
private readonly HtmlLocalLinkParser _localLinkParser;
private readonly RichTextEditorPastedImages _pastedImages;
+ private readonly IImageUrlGenerator _imageUrlGenerator;
public RichTextPropertyValueEditor(
DataEditorAttribute attribute,
@@ -88,13 +92,15 @@ namespace Umbraco.Web.PropertyEditors
IShortStringHelper shortStringHelper,
HtmlImageSourceParser imageSourceParser,
HtmlLocalLinkParser localLinkParser,
- RichTextEditorPastedImages pastedImages)
+ RichTextEditorPastedImages pastedImages,
+ IImageUrlGenerator imageUrlGenerator)
: base(dataTypeService, localizationService,localizedTextService, shortStringHelper, attribute)
{
_umbracoContextAccessor = umbracoContextAccessor;
_imageSourceParser = imageSourceParser;
_localLinkParser = localLinkParser;
_pastedImages = pastedImages;
+ _imageUrlGenerator = imageUrlGenerator;
}
///
@@ -148,7 +154,7 @@ namespace Umbraco.Web.PropertyEditors
var mediaParent = config?.MediaParentId;
var mediaParentId = mediaParent == null ? Guid.Empty : mediaParent.Guid;
- var parseAndSavedTempImages = _pastedImages.FindAndPersistPastedTempImages(editorValue.Value.ToString(), mediaParentId, userId);
+ var parseAndSavedTempImages = _pastedImages.FindAndPersistPastedTempImages(editorValue.Value.ToString(), mediaParentId, userId, _imageUrlGenerator);
var editorValueWithMediaUrlsRemoved = _imageSourceParser.RemoveImageSources(parseAndSavedTempImages);
var parsed = MacroTagParser.FormatRichTextContentForPersistence(editorValueWithMediaUrlsRemoved);
diff --git a/src/Umbraco.Web/Runtime/WebInitialComposer.cs b/src/Umbraco.Web/Runtime/WebInitialComposer.cs
index e283b4d6a0..7bb54fa5b0 100644
--- a/src/Umbraco.Web/Runtime/WebInitialComposer.cs
+++ b/src/Umbraco.Web/Runtime/WebInitialComposer.cs
@@ -47,6 +47,8 @@ using Umbraco.Web.WebApi;
using Current = Umbraco.Web.Composing.Current;
using Umbraco.Web.PropertyEditors;
using Umbraco.Examine;
+using Umbraco.Core.Models;
+using Umbraco.Web.Models;
namespace Umbraco.Web.Runtime
{
@@ -204,6 +206,8 @@ namespace Umbraco.Web.Runtime
composition.MediaUrlProviders()
.Append();
+ composition.RegisterUnique();
+
composition.RegisterUnique();
composition.ContentFinders()
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index d0936f0d6f..69b9e182c7 100755
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -148,6 +148,7 @@
+
@@ -156,6 +157,7 @@
+
@@ -172,6 +174,7 @@
+
diff --git a/src/Umbraco.Web/UrlHelperRenderExtensions.cs b/src/Umbraco.Web/UrlHelperRenderExtensions.cs
index 8e410bf584..0cf009cb88 100644
--- a/src/Umbraco.Web/UrlHelperRenderExtensions.cs
+++ b/src/Umbraco.Web/UrlHelperRenderExtensions.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Web;
using System.Web.Mvc;
using Umbraco.Core;
+using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors.ValueConverters;
using Umbraco.Web.Composing;
@@ -37,11 +38,11 @@ namespace Umbraco.Web
/// set to false if using the result of this method for CSS.
///
///
- public static IHtmlString GetCropUrl(this UrlHelper urlHelper, IPublishedContent mediaItem, string cropAlias, bool htmlEncode = true)
+ public static IHtmlString GetCropUrl(this UrlHelper urlHelper, IPublishedContent mediaItem, IImageUrlGenerator imageUrlGenerator, string cropAlias, bool htmlEncode = true)
{
if (mediaItem == null) return EmptyHtmlString;
- var url = mediaItem.GetCropUrl(cropAlias: cropAlias, useCropDimensions: true);
+ var url = mediaItem.GetCropUrl(imageUrlGenerator, cropAlias: cropAlias, useCropDimensions: true);
return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url);
}
@@ -65,11 +66,11 @@ namespace Umbraco.Web
///
/// The ImageProcessor.Web Url.
///
- public static IHtmlString GetCropUrl(this UrlHelper urlHelper, IPublishedContent mediaItem, string propertyAlias, string cropAlias, bool htmlEncode = true)
+ public static IHtmlString GetCropUrl(this UrlHelper urlHelper, IPublishedContent mediaItem, string propertyAlias, string cropAlias, IImageUrlGenerator imageUrlGenerator, bool htmlEncode = true)
{
if (mediaItem == null) return EmptyHtmlString;
- var url = mediaItem.GetCropUrl(propertyAlias: propertyAlias, cropAlias: cropAlias, useCropDimensions: true);
+ var url = mediaItem.GetCropUrl(imageUrlGenerator, propertyAlias: propertyAlias, cropAlias: cropAlias, useCropDimensions: true);
return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url);
}
@@ -133,6 +134,7 @@ namespace Umbraco.Web
///
public static IHtmlString GetCropUrl(this UrlHelper urlHelper,
IPublishedContent mediaItem,
+ IImageUrlGenerator imageUrlGenerator,
int? width = null,
int? height = null,
string propertyAlias = Umbraco.Core.Constants.Conventions.Media.File,
@@ -150,7 +152,7 @@ namespace Umbraco.Web
{
if (mediaItem == null) return EmptyHtmlString;
- var url = mediaItem.GetCropUrl(width, height, propertyAlias, cropAlias, quality, imageCropMode,
+ var url = mediaItem.GetCropUrl(imageUrlGenerator, width, height, propertyAlias, cropAlias, quality, imageCropMode,
imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, ratioMode,
upScale);
return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url);
@@ -216,6 +218,7 @@ namespace Umbraco.Web
///
public static IHtmlString GetCropUrl(this UrlHelper urlHelper,
string imageUrl,
+ IImageUrlGenerator imageUrlGenerator,
int? width = null,
int? height = null,
string imageCropperValue = null,
@@ -231,7 +234,7 @@ namespace Umbraco.Web
bool upScale = true,
bool htmlEncode = true)
{
- var url = imageUrl.GetCropUrl(width, height, imageCropperValue, cropAlias, quality, imageCropMode,
+ var url = imageUrl.GetCropUrl(imageUrlGenerator, width, height, imageCropperValue, cropAlias, quality, imageCropMode,
imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode,
upScale);
return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url);
@@ -239,6 +242,7 @@ namespace Umbraco.Web
public static IHtmlString GetCropUrl(this UrlHelper urlHelper,
ImageCropperValue imageCropperValue,
+ IImageUrlGenerator imageUrlGenerator,
int? width = null,
int? height = null,
string cropAlias = null,
@@ -256,7 +260,7 @@ namespace Umbraco.Web
if (imageCropperValue == null) return EmptyHtmlString;
var imageUrl = imageCropperValue.Src;
- var url = imageUrl.GetCropUrl(imageCropperValue, width, height, cropAlias, quality, imageCropMode,
+ var url = imageUrl.GetCropUrl(imageUrlGenerator, imageCropperValue, width, height, cropAlias, quality, imageCropMode,
imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode,
upScale);
return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url);