Introduce Image URL Generator abstraction
This commit is contained in:
@@ -5,6 +5,7 @@ using Umbraco.Core.Dictionary;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Mapping;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.PackageActions;
|
||||
using Umbraco.Core.Packaging;
|
||||
@@ -208,6 +209,8 @@ namespace Umbraco.Core.Composing
|
||||
public static IVariationContextAccessor VariationContextAccessor
|
||||
=> Factory.GetInstance<IVariationContextAccessor>();
|
||||
|
||||
public static IImageUrlGenerator ImageUrlGenerator
|
||||
=> Factory.GetInstance<IImageUrlGenerator>();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
7
src/Umbraco.Core/Models/IImageUrlGenerator.cs
Normal file
7
src/Umbraco.Core/Models/IImageUrlGenerator.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public interface IImageUrlGenerator
|
||||
{
|
||||
string GetImageUrl(ImageUrlGenerationOptions options);
|
||||
}
|
||||
}
|
||||
35
src/Umbraco.Core/Models/ImageUrlGenerationOptions.cs
Normal file
35
src/Umbraco.Core/Models/ImageUrlGenerationOptions.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public class ImageUrlGenerationOptions
|
||||
{
|
||||
public string ImageUrl { get; set; }
|
||||
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; }
|
||||
|
||||
public class FocalPointPosition
|
||||
{
|
||||
public decimal Left { get; set; }
|
||||
public decimal Top { get; set; }
|
||||
}
|
||||
|
||||
public class CropCoordinates
|
||||
{
|
||||
public decimal X1 { get; set; }
|
||||
public decimal Y1 { get; set; }
|
||||
public decimal X2 { get; set; }
|
||||
public decimal Y2 { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,13 +106,14 @@ namespace Umbraco.Core.Models
|
||||
|
||||
//use the custom avatar
|
||||
var avatarUrl = Current.MediaFileSystem.GetUrl(user.Avatar);
|
||||
var urlGenerator = Current.ImageUrlGenerator;
|
||||
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"
|
||||
urlGenerator.GetImageUrl(new ImageUrlGenerationOptions { ImageUrl = avatarUrl, ImageCropMode = "crop", Width = 30, Height = 30 }),
|
||||
urlGenerator.GetImageUrl(new ImageUrlGenerationOptions { ImageUrl = avatarUrl, ImageCropMode = "crop", Width = 60, Height = 60 }),
|
||||
urlGenerator.GetImageUrl(new ImageUrlGenerationOptions { ImageUrl = avatarUrl, ImageCropMode = "crop", Width = 90, Height = 90 }),
|
||||
urlGenerator.GetImageUrl(new ImageUrlGenerationOptions { ImageUrl = avatarUrl, ImageCropMode = "crop", Width = 150, Height = 150 }),
|
||||
urlGenerator.GetImageUrl(new ImageUrlGenerationOptions { ImageUrl = avatarUrl, ImageCropMode = "crop", Width = 300, Height = 300 })
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Serialization;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
@@ -59,38 +61,34 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
: Crops.FirstOrDefault(x => x.Alias.InvariantEquals(alias));
|
||||
}
|
||||
|
||||
internal void AppendCropBaseUrl(StringBuilder url, ImageCropperCrop crop, bool defaultCrop, bool preferFocalPoint)
|
||||
internal 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 { ImageUrl = url, FocalPoint = new ImageUrlGenerationOptions.FocalPointPosition { Left = FocalPoint.Left, Top = FocalPoint.Top } };
|
||||
}
|
||||
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 { ImageUrl = url, Crop = new ImageUrlGenerationOptions.CropCoordinates { X1 = crop.Coordinates.X1, X2 = crop.Coordinates.X2, Y1 = crop.Coordinates.Y1, Y2 = crop.Coordinates.Y2 } };
|
||||
}
|
||||
else
|
||||
{
|
||||
url.Append("?anchor=center");
|
||||
url.Append("&mode=crop");
|
||||
return new ImageUrlGenerationOptions { ImageUrl = url, DefaultCrop = true };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value image url for a specified crop.
|
||||
/// </summary>
|
||||
public string GetCropUrl(string alias, bool useCropDimensions = true, bool useFocalPoint = false, string cacheBusterValue = null)
|
||||
[Obsolete("Use the overload that takes an IImageUrlGenerator")]
|
||||
public string GetCropUrl(string alias, bool useCropDimensions = true, bool useFocalPoint = false, string cacheBusterValue = null) => GetCropUrl(alias, Current.ImageUrlGenerator, useCropDimensions, useFocalPoint, cacheBusterValue);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value image url for a specified crop.
|
||||
/// </summary>
|
||||
public string GetCropUrl(string alias, IImageUrlGenerator imageUrlGenerator, bool useCropDimensions = true, bool useFocalPoint = false, string cacheBusterValue = null)
|
||||
{
|
||||
var crop = GetCrop(alias);
|
||||
|
||||
@@ -98,38 +96,37 @@ 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value image url for a specific width and height.
|
||||
/// </summary>
|
||||
public string GetCropUrl(int width, int height, bool useFocalPoint = false, string cacheBusterValue = null)
|
||||
[Obsolete("Use the overload that takes an IImageUrlGenerator")]
|
||||
public string GetCropUrl(int width, int height, bool useFocalPoint = false, string cacheBusterValue = null) => GetCropUrl(width, height, Current.ImageUrlGenerator, useFocalPoint, cacheBusterValue);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value image url for a specific width and height.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -132,6 +132,8 @@
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\Models\PropertyDataDto80.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\Models\PropertyTypeDto80.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_6_0\AddMainDomLock.cs" />
|
||||
<Compile Include="Models\IImageUrlGenerator.cs" />
|
||||
<Compile Include="Models\ImageUrlGenerationOptions.cs" />
|
||||
<Compile Include="Runtime\IMainDomLock.cs" />
|
||||
<Compile Include="Runtime\MainDomSemaphoreLock.cs" />
|
||||
<Compile Include="Runtime\SqlMainDomLock.cs" />
|
||||
|
||||
@@ -21,6 +21,7 @@ using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.PropertyEditors;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.Tests.PropertyEditors
|
||||
{
|
||||
@@ -110,7 +111,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
[Test]
|
||||
public void GetCropUrl_CropAliasTest()
|
||||
{
|
||||
var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, cropAlias: "Thumb", useCropDimensions: true);
|
||||
var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, cropAlias: "Thumb", useCropDimensions: true);
|
||||
Assert.AreEqual(MediaPath + "?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&width=100&height=100", urlString);
|
||||
}
|
||||
|
||||
@@ -120,28 +121,28 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
[Test]
|
||||
public void GetCropUrl_CropAliasIgnoreWidthHeightTest()
|
||||
{
|
||||
var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, cropAlias: "Thumb", useCropDimensions: true, width: 50, height: 50);
|
||||
var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), 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);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetCropUrl_WidthHeightTest()
|
||||
{
|
||||
var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, width: 200, height: 300);
|
||||
var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, 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 = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, cropAlias: "thumb", preferFocalPoint: true, useCropDimensions: true);
|
||||
var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, cropAlias: "thumb", preferFocalPoint: true, useCropDimensions: true);
|
||||
Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&width=100&height=100", urlString);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetCropUrlFurtherOptionsTest()
|
||||
{
|
||||
var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, width: 200, height: 300, furtherOptions: "&filter=comic&roundedcorners=radius-26|bgcolor-fff");
|
||||
var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), 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);
|
||||
}
|
||||
|
||||
@@ -151,7 +152,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);
|
||||
}
|
||||
|
||||
@@ -162,7 +163,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
public void GetBaseCropUrlFromModelTest()
|
||||
{
|
||||
var cropDataSet = CropperJson1.DeserializeImageCropperValue();
|
||||
var urlString = cropDataSet.GetCropUrl("thumb");
|
||||
var urlString = cropDataSet.GetCropUrl("thumb", new TestImageUrlGenerator());
|
||||
Assert.AreEqual("?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&width=100&height=100", urlString);
|
||||
}
|
||||
|
||||
@@ -172,7 +173,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
[Test]
|
||||
public void GetCropUrl_CropAliasHeightRatioModeTest()
|
||||
{
|
||||
var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, cropAlias: "Thumb", useCropDimensions: true, ratioMode:ImageCropRatioMode.Height);
|
||||
var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), 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);
|
||||
}
|
||||
|
||||
@@ -182,7 +183,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
[Test]
|
||||
public void GetCropUrl_WidthHeightRatioModeTest()
|
||||
{
|
||||
var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, width: 300, height: 150, ratioMode:ImageCropRatioMode.Height);
|
||||
var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), 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);
|
||||
}
|
||||
|
||||
@@ -192,7 +193,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
[Test]
|
||||
public void GetCropUrl_HeightWidthRatioModeTest()
|
||||
{
|
||||
var urlString = MediaPath.GetCropUrl(imageCropperValue: CropperJson1, width: 300, height: 150, ratioMode: ImageCropRatioMode.Width);
|
||||
var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: CropperJson1, width: 300, height: 150, ratioMode: ImageCropRatioMode.Width);
|
||||
Assert.AreEqual(MediaPath + "?center=0.80827067669172936,0.96&mode=crop&height=150&widthratio=2", urlString);
|
||||
}
|
||||
|
||||
@@ -202,11 +203,11 @@ 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);
|
||||
@@ -221,7 +222,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
[Test]
|
||||
public void GetCropUrl_UploadTypeTest()
|
||||
{
|
||||
var urlString = MediaPath.GetCropUrl(width: 100, height: 270, imageCropMode: ImageCropMode.Crop, imageCropAnchor: ImageCropAnchor.Center);
|
||||
var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), width: 100, height: 270, imageCropMode: ImageCropMode.Crop, imageCropAnchor: ImageCropAnchor.Center);
|
||||
Assert.AreEqual(MediaPath + "?mode=crop&anchor=center&width=100&height=270", urlString);
|
||||
}
|
||||
|
||||
@@ -233,7 +234,7 @@ 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);
|
||||
var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: cropperJson, width: 300, height: 150, preferFocalPoint:true);
|
||||
Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&width=300&height=150", urlString);
|
||||
}
|
||||
|
||||
@@ -245,7 +246,7 @@ 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);
|
||||
var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: cropperJson, cropAlias: "home", width: 200);
|
||||
Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&heightratio=0.5962962962962962962962962963&width=200", urlString);
|
||||
}
|
||||
|
||||
@@ -257,7 +258,7 @@ 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);
|
||||
var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: cropperJson, cropAlias: "home", width: 200);
|
||||
Assert.AreEqual(MediaPath + "?center=0.41,0.4275&mode=crop&heightratio=0.5962962962962962962962962963&width=200", urlString);
|
||||
}
|
||||
|
||||
@@ -269,7 +270,7 @@ 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);
|
||||
var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: cropperJson, cropAlias: "home", width: 200, useCropDimensions: true);
|
||||
Assert.AreEqual(MediaPath + "?center=0.41,0.4275&mode=crop&width=270&height=161", urlString);
|
||||
}
|
||||
|
||||
@@ -281,7 +282,7 @@ 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);
|
||||
var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: cropperJson, cropAlias: "home", height: 200);
|
||||
Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&widthratio=1.6770186335403726708074534161&height=200", urlString);
|
||||
}
|
||||
|
||||
@@ -293,7 +294,7 @@ 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);
|
||||
var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: cropperJson, width: 200);
|
||||
Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&width=200", urlString);
|
||||
}
|
||||
|
||||
@@ -305,7 +306,7 @@ 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);
|
||||
var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), imageCropperValue: cropperJson, height: 200);
|
||||
Assert.AreEqual(MediaPath + "?anchor=center&mode=crop&height=200", urlString);
|
||||
}
|
||||
|
||||
@@ -317,8 +318,57 @@ 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");
|
||||
var urlString = MediaPath.GetCropUrl(new TestImageUrlGenerator(), 400, 400, cropperJson, imageCropMode: ImageCropMode.Pad, furtherOptions: "&bgcolor=fff");
|
||||
Assert.AreEqual(MediaPath + "?mode=pad&width=400&height=400&bgcolor=fff", urlString);
|
||||
}
|
||||
|
||||
private class TestImageUrlGenerator : IImageUrlGenerator
|
||||
{
|
||||
public string GetImageUrl(ImageUrlGenerationOptions options)
|
||||
{
|
||||
var imageProcessorUrl = new StringBuilder(options.ImageUrl ?? string.Empty);
|
||||
|
||||
if (options.FocalPoint != null)
|
||||
{
|
||||
imageProcessorUrl.Append("?center=");
|
||||
imageProcessorUrl.Append(options.FocalPoint.Top.ToString(CultureInfo.InvariantCulture));
|
||||
imageProcessorUrl.Append(",");
|
||||
imageProcessorUrl.Append(options.FocalPoint.Left.ToString(CultureInfo.InvariantCulture));
|
||||
imageProcessorUrl.Append("&mode=crop");
|
||||
}
|
||||
else if (options.Crop != null)
|
||||
{
|
||||
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");
|
||||
}
|
||||
else if (options.DefaultCrop)
|
||||
{
|
||||
imageProcessorUrl.Append("?anchor=center&mode=crop");
|
||||
}
|
||||
else
|
||||
{
|
||||
imageProcessorUrl.Append("?mode=" + options.ImageCropMode.ToString().ToLower());
|
||||
if (options.ImageCropAnchor != null)imageProcessorUrl.Append("&anchor=" + options.ImageCropAnchor.ToString().ToLower());
|
||||
}
|
||||
|
||||
var hasFormat = options.FurtherOptions != null && options.FurtherOptions.InvariantContains("&format=");
|
||||
if (options.Quality != null && hasFormat == false) imageProcessorUrl.Append("&quality=" + options.Quality);
|
||||
if (options.HeightRatio != null) imageProcessorUrl.Append("&heightratio=" + options.HeightRatio.Value.ToString(CultureInfo.InvariantCulture));
|
||||
if (options.WidthRatio != null) imageProcessorUrl.Append("&widthratio=" + options.WidthRatio.Value.ToString(CultureInfo.InvariantCulture));
|
||||
if (options.Width != null) imageProcessorUrl.Append("&width=" + options.Width);
|
||||
if (options.Height != null) imageProcessorUrl.Append("&height=" + options.Height);
|
||||
if (options.UpScale == false) imageProcessorUrl.Append("&upscale=false");
|
||||
if (options.AnimationProcessMode != null) imageProcessorUrl.Append("&animationprocessmode=" + options.AnimationProcessMode);
|
||||
if (options.FurtherOptions != null) imageProcessorUrl.Append(options.FurtherOptions);
|
||||
if (options.Quality != null && hasFormat) imageProcessorUrl.Append("&quality=" + options.Quality);
|
||||
if (options.CacheBusterValue != null) imageProcessorUrl.Append("&rnd=").Append(options.CacheBusterValue);
|
||||
|
||||
return imageProcessorUrl.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ using Umbraco.Web.PropertyEditors;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.Templates;
|
||||
using Umbraco.Web.Models;
|
||||
|
||||
namespace Umbraco.Tests.PublishedContent
|
||||
{
|
||||
@@ -46,7 +47,7 @@ namespace Umbraco.Tests.PublishedContent
|
||||
var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, logger, Mock.Of<IMediaService>(), Mock.Of<IContentTypeBaseServiceProvider>());
|
||||
var localLinkParser = new HtmlLocalLinkParser(umbracoContextAccessor);
|
||||
var dataTypeService = new TestObjects.TestDataTypeService(
|
||||
new DataType(new RichTextPropertyEditor(logger, umbracoContextAccessor, imageSourceParser, localLinkParser, pastedImages)) { Id = 1 });
|
||||
new DataType(new RichTextPropertyEditor(logger, umbracoContextAccessor, imageSourceParser, localLinkParser, pastedImages, Mock.Of<IImageUrlGenerator>())) { Id = 1 });
|
||||
|
||||
var publishedContentTypeFactory = new PublishedContentTypeFactory(Mock.Of<IPublishedModelFactory>(), converters, dataTypeService);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
namespace Umbraco.Tests.PublishedContent
|
||||
{
|
||||
@@ -53,7 +54,7 @@ namespace Umbraco.Tests.PublishedContent
|
||||
var dataTypeService = new TestObjects.TestDataTypeService(
|
||||
new DataType(new VoidEditor(logger)) { Id = 1 },
|
||||
new DataType(new TrueFalsePropertyEditor(logger)) { Id = 1001 },
|
||||
new DataType(new RichTextPropertyEditor(logger, umbracoContextAccessor, imageSourceParser, linkParser, pastedImages)) { Id = 1002 },
|
||||
new DataType(new RichTextPropertyEditor(logger, umbracoContextAccessor, imageSourceParser, linkParser, pastedImages, Mock.Of<IImageUrlGenerator>())) { Id = 1002 },
|
||||
new DataType(new IntegerPropertyEditor(logger)) { Id = 1003 },
|
||||
new DataType(new TextboxPropertyEditor(logger)) { Id = 1004 },
|
||||
new DataType(new MediaPickerPropertyEditor(logger)) { Id = 1005 });
|
||||
|
||||
@@ -97,6 +97,7 @@ namespace Umbraco.Tests.Runtimes
|
||||
composition.Register<IVariationContextAccessor, TestVariationContextAccessor>(Lifetime.Singleton);
|
||||
composition.Register<IDefaultCultureAccessor, TestDefaultCultureAccessor>(Lifetime.Singleton);
|
||||
composition.Register<ISiteDomainHelper>(_ => Mock.Of<ISiteDomainHelper>(), Lifetime.Singleton);
|
||||
composition.Register(_ => Mock.Of<IImageUrlGenerator>(), Lifetime.Singleton);
|
||||
composition.RegisterUnique(f => new DistributedCache());
|
||||
composition.WithCollectionBuilder<UrlProviderCollectionBuilder>().Append<DefaultUrlProvider>();
|
||||
composition.RegisterUnique<IDistributedCacheBinder, DistributedCacheBinder>();
|
||||
|
||||
@@ -43,6 +43,7 @@ using Current = Umbraco.Core.Composing.Current;
|
||||
using FileSystems = Umbraco.Core.IO.FileSystems;
|
||||
using Umbraco.Web.Templates;
|
||||
using Umbraco.Web.PropertyEditors;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Tests.Testing
|
||||
{
|
||||
@@ -248,6 +249,7 @@ namespace Umbraco.Tests.Testing
|
||||
var runtimeStateMock = new Mock<IRuntimeState>();
|
||||
runtimeStateMock.Setup(x => x.Level).Returns(RuntimeLevel.Run);
|
||||
Composition.RegisterUnique(f => runtimeStateMock.Object);
|
||||
Composition.Register(_ => Mock.Of<IImageUrlGenerator>());
|
||||
|
||||
// ah...
|
||||
Composition.WithCollectionBuilder<ActionCollectionBuilder>();
|
||||
|
||||
@@ -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 = ImageCropperTemplateExtensions.GetCropUrl(url,
|
||||
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;
|
||||
|
||||
|
||||
<img src="@url" alt="@altText">
|
||||
|
||||
if (Model.value.caption != null)
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Media;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.WebApi;
|
||||
@@ -19,11 +21,17 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
private readonly IMediaFileSystem _mediaFileSystem;
|
||||
private readonly IContentSection _contentSection;
|
||||
private readonly IImageUrlGenerator _imageUrlGenerator;
|
||||
|
||||
public ImagesController(IMediaFileSystem mediaFileSystem, IContentSection contentSection)
|
||||
[Obsolete("This constructor will be removed in a future release. Please use the constructor with the IImageUrlGenerator overload")]
|
||||
public ImagesController(IMediaFileSystem mediaFileSystem, IContentSection contentSection) : this (mediaFileSystem, contentSection, Current.ImageUrlGenerator)
|
||||
{
|
||||
}
|
||||
public ImagesController(IMediaFileSystem mediaFileSystem, IContentSection contentSection, IImageUrlGenerator imageUrlGenerator)
|
||||
{
|
||||
_mediaFileSystem = mediaFileSystem;
|
||||
_contentSection = contentSection;
|
||||
_imageUrlGenerator = imageUrlGenerator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -75,12 +83,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 { ImageUrl = 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;
|
||||
}
|
||||
|
||||
|
||||
389
src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs
Normal file
389
src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs
Normal file
@@ -0,0 +1,389 @@
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the ImageProcessor Url by the crop alias (from the "umbracoFile" property alias) on the IPublishedContent item
|
||||
/// </summary>
|
||||
/// <param name="mediaItem">
|
||||
/// The IPublishedContent item.
|
||||
/// </param>
|
||||
/// <param name="cropAlias">
|
||||
/// The crop alias e.g. thumbnail
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The ImageProcessor.Web Url.
|
||||
/// </returns>
|
||||
public static string GetCropUrl(this IPublishedContent mediaItem, string cropAlias, IImageUrlGenerator imageUrlGenerator)
|
||||
{
|
||||
return mediaItem.GetCropUrl(imageUrlGenerator, cropAlias: cropAlias, useCropDimensions: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImageProcessor Url by the crop alias using the specified property containing the image cropper Json data on the IPublishedContent item.
|
||||
/// </summary>
|
||||
/// <param name="mediaItem">
|
||||
/// The IPublishedContent item.
|
||||
/// </param>
|
||||
/// <param name="propertyAlias">
|
||||
/// The property alias of the property containing the Json data e.g. umbracoFile
|
||||
/// </param>
|
||||
/// <param name="cropAlias">
|
||||
/// The crop alias e.g. thumbnail
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The ImageProcessor.Web Url.
|
||||
/// </returns>
|
||||
public static string GetCropUrl(this IPublishedContent mediaItem, string propertyAlias, string cropAlias, IImageUrlGenerator imageUrlGenerator)
|
||||
{
|
||||
return mediaItem.GetCropUrl(imageUrlGenerator, propertyAlias: propertyAlias, cropAlias: cropAlias, useCropDimensions: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImageProcessor Url from the IPublishedContent item.
|
||||
/// </summary>
|
||||
/// <param name="mediaItem">
|
||||
/// The IPublishedContent item.
|
||||
/// </param>
|
||||
/// <param name="width">
|
||||
/// The width of the output image.
|
||||
/// </param>
|
||||
/// <param name="height">
|
||||
/// The height of the output image.
|
||||
/// </param>
|
||||
/// <param name="propertyAlias">
|
||||
/// Property alias of the property containing the Json data.
|
||||
/// </param>
|
||||
/// <param name="cropAlias">
|
||||
/// The crop alias.
|
||||
/// </param>
|
||||
/// <param name="quality">
|
||||
/// Quality percentage of the output image.
|
||||
/// </param>
|
||||
/// <param name="imageCropMode">
|
||||
/// The image crop mode.
|
||||
/// </param>
|
||||
/// <param name="imageCropAnchor">
|
||||
/// The image crop anchor.
|
||||
/// </param>
|
||||
/// <param name="preferFocalPoint">
|
||||
/// Use focal point, to generate an output image using the focal point instead of the predefined crop
|
||||
/// </param>
|
||||
/// <param name="useCropDimensions">
|
||||
/// Use crop dimensions to have the output image sized according to the predefined crop sizes, this will override the width and height parameters.
|
||||
/// </param>
|
||||
/// <param name="cacheBuster">
|
||||
/// Add a serialized date of the last edit of the item to ensure client cache refresh when updated
|
||||
/// </param>
|
||||
/// <param name="furtherOptions">
|
||||
/// These are any query string parameters (formatted as query strings) that ImageProcessor supports. For example:
|
||||
/// <example>
|
||||
/// <![CDATA[
|
||||
/// furtherOptions: "&bgcolor=fff"
|
||||
/// ]]>
|
||||
/// </example>
|
||||
/// </param>
|
||||
/// <param name="ratioMode">
|
||||
/// Use a dimension as a ratio
|
||||
/// </param>
|
||||
/// <param name="upScale">
|
||||
/// If the image should be upscaled to requested dimensions
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="string"/>.
|
||||
/// </returns>
|
||||
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<ImageCropperValue>();
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImageProcessor Url from the image path.
|
||||
/// </summary>
|
||||
/// <param name="imageUrl">
|
||||
/// The image url.
|
||||
/// </param>
|
||||
/// <param name="width">
|
||||
/// The width of the output image.
|
||||
/// </param>
|
||||
/// <param name="height">
|
||||
/// The height of the output image.
|
||||
/// </param>
|
||||
/// <param name="imageCropperValue">
|
||||
/// The Json data from the Umbraco Core Image Cropper property editor
|
||||
/// </param>
|
||||
/// <param name="cropAlias">
|
||||
/// The crop alias.
|
||||
/// </param>
|
||||
/// <param name="quality">
|
||||
/// Quality percentage of the output image.
|
||||
/// </param>
|
||||
/// <param name="imageCropMode">
|
||||
/// The image crop mode.
|
||||
/// </param>
|
||||
/// <param name="imageCropAnchor">
|
||||
/// The image crop anchor.
|
||||
/// </param>
|
||||
/// <param name="preferFocalPoint">
|
||||
/// Use focal point to generate an output image using the focal point instead of the predefined crop if there is one
|
||||
/// </param>
|
||||
/// <param name="useCropDimensions">
|
||||
/// Use crop dimensions to have the output image sized according to the predefined crop sizes, this will override the width and height parameters
|
||||
/// </param>
|
||||
/// <param name="cacheBusterValue">
|
||||
/// Add a serialized date of the last edit of the item to ensure client cache refresh when updated
|
||||
/// </param>
|
||||
/// <param name="furtherOptions">
|
||||
/// These are any query string parameters (formatted as query strings) that ImageProcessor supports. For example:
|
||||
/// <example>
|
||||
/// <![CDATA[
|
||||
/// furtherOptions: "&bgcolor=fff"
|
||||
/// ]]>
|
||||
/// </example>
|
||||
/// </param>
|
||||
/// <param name="ratioMode">
|
||||
/// Use a dimension as a ratio
|
||||
/// </param>
|
||||
/// <param name="upScale">
|
||||
/// If the image should be upscaled to requested dimensions
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="string"/>.
|
||||
/// </returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImageProcessor Url from the image path.
|
||||
/// </summary>
|
||||
/// <param name="imageUrl">
|
||||
/// The image url.
|
||||
/// </param>
|
||||
/// <param name="imageUrlGenerator">
|
||||
/// The generator that will process all the options and the image URL to return a full image urls with all processing options appended
|
||||
/// </param>
|
||||
/// <param name="cropDataSet"></param>
|
||||
/// <param name="width">
|
||||
/// The width of the output image.
|
||||
/// </param>
|
||||
/// <param name="height">
|
||||
/// The height of the output image.
|
||||
/// </param>
|
||||
/// <param name="cropAlias">
|
||||
/// The crop alias.
|
||||
/// </param>
|
||||
/// <param name="quality">
|
||||
/// Quality percentage of the output image.
|
||||
/// </param>
|
||||
/// <param name="imageCropMode">
|
||||
/// The image crop mode.
|
||||
/// </param>
|
||||
/// <param name="imageCropAnchor">
|
||||
/// The image crop anchor.
|
||||
/// </param>
|
||||
/// <param name="preferFocalPoint">
|
||||
/// Use focal point to generate an output image using the focal point instead of the predefined crop if there is one
|
||||
/// </param>
|
||||
/// <param name="useCropDimensions">
|
||||
/// Use crop dimensions to have the output image sized according to the predefined crop sizes, this will override the width and height parameters
|
||||
/// </param>
|
||||
/// <param name="cacheBusterValue">
|
||||
/// Add a serialized date of the last edit of the item to ensure client cache refresh when updated
|
||||
/// </param>
|
||||
/// <param name="furtherOptions">
|
||||
/// These are any query string parameters (formatted as query strings) that ImageProcessor supports. For example:
|
||||
/// <example>
|
||||
/// <![CDATA[
|
||||
/// furtherOptions: "&bgcolor=fff"
|
||||
/// ]]>
|
||||
/// </example>
|
||||
/// </param>
|
||||
/// <param name="ratioMode">
|
||||
/// Use a dimension as a ratio
|
||||
/// </param>
|
||||
/// <param name="upScale">
|
||||
/// If the image should be upscaled to requested dimensions
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="string"/>.
|
||||
/// </returns>
|
||||
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)
|
||||
{
|
||||
if (string.IsNullOrEmpty(imageUrl) == false)
|
||||
{
|
||||
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 = 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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,10 +29,7 @@ namespace Umbraco.Web
|
||||
/// <returns>
|
||||
/// The ImageProcessor.Web Url.
|
||||
/// </returns>
|
||||
public static string GetCropUrl(this IPublishedContent mediaItem, string cropAlias)
|
||||
{
|
||||
return mediaItem.GetCropUrl(cropAlias: cropAlias, useCropDimensions: true);
|
||||
}
|
||||
public static string GetCropUrl(this IPublishedContent mediaItem, string cropAlias) => ImageCropperTemplateCoreExtensions.GetCropUrl(mediaItem, cropAlias, Current.ImageUrlGenerator);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImageProcessor Url by the crop alias using the specified property containing the image cropper Json data on the IPublishedContent item.
|
||||
@@ -49,10 +46,7 @@ namespace Umbraco.Web
|
||||
/// <returns>
|
||||
/// The ImageProcessor.Web Url.
|
||||
/// </returns>
|
||||
public static string GetCropUrl(this IPublishedContent mediaItem, string propertyAlias, string cropAlias)
|
||||
{
|
||||
return mediaItem.GetCropUrl(propertyAlias: propertyAlias, cropAlias: cropAlias, useCropDimensions: true);
|
||||
}
|
||||
public static string GetCropUrl(this IPublishedContent mediaItem, string propertyAlias, string cropAlias) => ImageCropperTemplateCoreExtensions.GetCropUrl(mediaItem, propertyAlias, cropAlias, Current.ImageUrlGenerator);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImageProcessor Url from the IPublishedContent item.
|
||||
@@ -121,44 +115,7 @@ namespace Umbraco.Web
|
||||
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<ImageCropperValue>();
|
||||
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);
|
||||
}
|
||||
bool upScale = true) => ImageCropperTemplateCoreExtensions.GetCropUrl(mediaItem, Current.ImageUrlGenerator, width, height, propertyAlias, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, ratioMode, upScale);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImageProcessor Url from the image path.
|
||||
@@ -227,19 +184,7 @@ namespace Umbraco.Web
|
||||
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);
|
||||
}
|
||||
bool upScale = true) => ImageCropperTemplateCoreExtensions.GetCropUrl(imageUrl, Current.ImageUrlGenerator, width, height, imageCropperValue, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode, upScale);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImageProcessor Url from the image path.
|
||||
@@ -306,129 +251,8 @@ namespace Umbraco.Web
|
||||
string cacheBusterValue = null,
|
||||
string furtherOptions = null,
|
||||
ImageCropRatioMode? ratioMode = null,
|
||||
bool upScale = true)
|
||||
{
|
||||
if (string.IsNullOrEmpty(imageUrl) == false)
|
||||
{
|
||||
var imageProcessorUrl = new StringBuilder();
|
||||
bool upScale = true) => ImageCropperTemplateCoreExtensions.GetCropUrl(imageUrl, Current.ImageUrlGenerator, cropDataSet, width, height, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode, upScale);
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
108
src/Umbraco.Web/Models/ImageProcessorImageUrlGenerator.cs
Normal file
108
src/Umbraco.Web/Models/ImageProcessorImageUrlGenerator.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
internal class ImageProcessorImageUrlGenerator : IImageUrlGenerator
|
||||
{
|
||||
public string GetImageUrl(ImageUrlGenerationOptions options)
|
||||
{
|
||||
var imageProcessorUrl = new StringBuilder(options.ImageUrl ?? string.Empty);
|
||||
|
||||
if (options.FocalPoint != null)
|
||||
{
|
||||
imageProcessorUrl.Append("?center=");
|
||||
imageProcessorUrl.Append(options.FocalPoint.Top.ToString(CultureInfo.InvariantCulture));
|
||||
imageProcessorUrl.Append(",");
|
||||
imageProcessorUrl.Append(options.FocalPoint.Left.ToString(CultureInfo.InvariantCulture));
|
||||
imageProcessorUrl.Append("&mode=crop");
|
||||
}
|
||||
else if (options.Crop != null)
|
||||
{
|
||||
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");
|
||||
}
|
||||
else if (options.DefaultCrop)
|
||||
{
|
||||
imageProcessorUrl.Append("?anchor=center");
|
||||
imageProcessorUrl.Append("&mode=crop");
|
||||
}
|
||||
else
|
||||
{
|
||||
imageProcessorUrl.Append("?mode=" + options.ImageCropMode.ToString().ToLower());
|
||||
|
||||
if (options.ImageCropAnchor != null)
|
||||
{
|
||||
imageProcessorUrl.Append("&anchor=" + options.ImageCropAnchor.ToString().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=" + options.Quality);
|
||||
}
|
||||
|
||||
if (options.HeightRatio != null)
|
||||
{
|
||||
imageProcessorUrl.Append("&heightratio=" + options.HeightRatio.Value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
if (options.WidthRatio != null)
|
||||
{
|
||||
imageProcessorUrl.Append("&widthratio=" + options.WidthRatio.Value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
if (options.Width != null)
|
||||
{
|
||||
imageProcessorUrl.Append("&width=" + options.Width);
|
||||
}
|
||||
|
||||
if (options.Height != null)
|
||||
{
|
||||
imageProcessorUrl.Append("&height=" + options.Height);
|
||||
}
|
||||
|
||||
if (options.UpScale == false)
|
||||
{
|
||||
imageProcessorUrl.Append("&upscale=false");
|
||||
}
|
||||
|
||||
if (options.AnimationProcessMode != null)
|
||||
{
|
||||
imageProcessorUrl.Append("&animationprocessmode=" + 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=" + options.Quality);
|
||||
}
|
||||
|
||||
if (options.CacheBusterValue != null)
|
||||
{
|
||||
imageProcessorUrl.Append("&rnd=").Append(options.CacheBusterValue);
|
||||
}
|
||||
|
||||
return imageProcessorUrl.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Editors;
|
||||
@@ -30,18 +31,31 @@ namespace Umbraco.Web.PropertyEditors
|
||||
private readonly HtmlImageSourceParser _imageSourceParser;
|
||||
private readonly RichTextEditorPastedImages _pastedImages;
|
||||
private readonly HtmlLocalLinkParser _localLinkParser;
|
||||
private readonly IImageUrlGenerator _imageUrlGenerator;
|
||||
|
||||
[Obsolete("Use the constructor which takes an IImageUrlGenerator")]
|
||||
public GridPropertyEditor(ILogger logger,
|
||||
IUmbracoContextAccessor umbracoContextAccessor,
|
||||
HtmlImageSourceParser imageSourceParser,
|
||||
RichTextEditorPastedImages pastedImages,
|
||||
HtmlLocalLinkParser localLinkParser)
|
||||
: this(logger, umbracoContextAccessor, imageSourceParser, pastedImages, localLinkParser, Current.ImageUrlGenerator)
|
||||
{
|
||||
}
|
||||
|
||||
public GridPropertyEditor(ILogger logger,
|
||||
IUmbracoContextAccessor umbracoContextAccessor,
|
||||
HtmlImageSourceParser imageSourceParser,
|
||||
RichTextEditorPastedImages pastedImages,
|
||||
HtmlLocalLinkParser localLinkParser,
|
||||
IImageUrlGenerator imageUrlGenerator)
|
||||
: base(logger)
|
||||
{
|
||||
_umbracoContextAccessor = umbracoContextAccessor;
|
||||
_imageSourceParser = imageSourceParser;
|
||||
_pastedImages = pastedImages;
|
||||
_localLinkParser = localLinkParser;
|
||||
_imageUrlGenerator = imageUrlGenerator;
|
||||
}
|
||||
|
||||
public override IPropertyIndexValueFactory PropertyIndexValueFactory => new GridPropertyIndexValueFactory();
|
||||
@@ -50,7 +64,7 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// Overridden to ensure that the value is validated
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected override IDataValueEditor CreateValueEditor() => new GridPropertyValueEditor(Attribute, _umbracoContextAccessor, _imageSourceParser, _pastedImages, _localLinkParser);
|
||||
protected override IDataValueEditor CreateValueEditor() => new GridPropertyValueEditor(Attribute, _umbracoContextAccessor, _imageSourceParser, _pastedImages, _localLinkParser, _imageUrlGenerator);
|
||||
|
||||
protected override IConfigurationEditor CreateConfigurationEditor() => new GridConfigurationEditor();
|
||||
|
||||
@@ -61,19 +75,32 @@ namespace Umbraco.Web.PropertyEditors
|
||||
private readonly RichTextEditorPastedImages _pastedImages;
|
||||
private readonly RichTextPropertyEditor.RichTextPropertyValueEditor _richTextPropertyValueEditor;
|
||||
private readonly MediaPickerPropertyEditor.MediaPickerPropertyValueEditor _mediaPickerPropertyValueEditor;
|
||||
private readonly IImageUrlGenerator _imageUrlGenerator;
|
||||
|
||||
[Obsolete("Use the constructor which takes an IImageUrlGenerator")]
|
||||
public GridPropertyValueEditor(DataEditorAttribute attribute,
|
||||
IUmbracoContextAccessor umbracoContextAccessor,
|
||||
HtmlImageSourceParser imageSourceParser,
|
||||
RichTextEditorPastedImages pastedImages,
|
||||
HtmlLocalLinkParser localLinkParser)
|
||||
: this(attribute, umbracoContextAccessor, imageSourceParser, pastedImages, localLinkParser, Current.ImageUrlGenerator)
|
||||
{
|
||||
}
|
||||
|
||||
public GridPropertyValueEditor(DataEditorAttribute attribute,
|
||||
IUmbracoContextAccessor umbracoContextAccessor,
|
||||
HtmlImageSourceParser imageSourceParser,
|
||||
RichTextEditorPastedImages pastedImages,
|
||||
HtmlLocalLinkParser localLinkParser,
|
||||
IImageUrlGenerator imageUrlGenerator)
|
||||
: base(attribute)
|
||||
{
|
||||
_umbracoContextAccessor = umbracoContextAccessor;
|
||||
_imageSourceParser = imageSourceParser;
|
||||
_pastedImages = pastedImages;
|
||||
_richTextPropertyValueEditor = new RichTextPropertyEditor.RichTextPropertyValueEditor(attribute, umbracoContextAccessor, imageSourceParser, localLinkParser, pastedImages);
|
||||
_richTextPropertyValueEditor = new RichTextPropertyEditor.RichTextPropertyValueEditor(attribute, umbracoContextAccessor, imageSourceParser, localLinkParser, pastedImages, _imageUrlGenerator);
|
||||
_mediaPickerPropertyValueEditor = new MediaPickerPropertyEditor.MediaPickerPropertyValueEditor(attribute);
|
||||
_imageUrlGenerator = imageUrlGenerator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -108,7 +135,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;
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// <param name="mediaParentFolder"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
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
|
||||
@@ -109,7 +109,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 { ImageUrl = location, ImageCropMode = "max", Width = width, Height = height });
|
||||
}
|
||||
|
||||
img.SetAttributeValue("src", location);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Editors;
|
||||
@@ -30,25 +31,36 @@ namespace Umbraco.Web.PropertyEditors
|
||||
private readonly HtmlImageSourceParser _imageSourceParser;
|
||||
private readonly HtmlLocalLinkParser _localLinkParser;
|
||||
private readonly RichTextEditorPastedImages _pastedImages;
|
||||
private readonly IImageUrlGenerator _imageUrlGenerator;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The constructor will setup the property editor based on the attribute if one is found
|
||||
/// </summary>
|
||||
[Obsolete("Use the constructor which takes an IImageUrlGenerator")]
|
||||
public RichTextPropertyEditor(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, HtmlImageSourceParser imageSourceParser, HtmlLocalLinkParser localLinkParser, RichTextEditorPastedImages pastedImages)
|
||||
: this(logger, umbracoContextAccessor, imageSourceParser, localLinkParser, pastedImages, Current.ImageUrlGenerator)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The constructor will setup the property editor based on the attribute if one is found
|
||||
/// </summary>
|
||||
public RichTextPropertyEditor(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, HtmlImageSourceParser imageSourceParser, HtmlLocalLinkParser localLinkParser, RichTextEditorPastedImages pastedImages, IImageUrlGenerator imageUrlGenerator)
|
||||
: base(logger)
|
||||
{
|
||||
_umbracoContextAccessor = umbracoContextAccessor;
|
||||
_imageSourceParser = imageSourceParser;
|
||||
_localLinkParser = localLinkParser;
|
||||
_pastedImages = pastedImages;
|
||||
_imageUrlGenerator = imageUrlGenerator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a custom value editor
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected override IDataValueEditor CreateValueEditor() => new RichTextPropertyValueEditor(Attribute, _umbracoContextAccessor, _imageSourceParser, _localLinkParser, _pastedImages);
|
||||
protected override IDataValueEditor CreateValueEditor() => new RichTextPropertyValueEditor(Attribute, _umbracoContextAccessor, _imageSourceParser, _localLinkParser, _pastedImages, _imageUrlGenerator);
|
||||
|
||||
protected override IConfigurationEditor CreateConfigurationEditor() => new RichTextConfigurationEditor();
|
||||
|
||||
@@ -63,14 +75,16 @@ namespace Umbraco.Web.PropertyEditors
|
||||
private readonly HtmlImageSourceParser _imageSourceParser;
|
||||
private readonly HtmlLocalLinkParser _localLinkParser;
|
||||
private readonly RichTextEditorPastedImages _pastedImages;
|
||||
private readonly IImageUrlGenerator _imageUrlGenerator;
|
||||
|
||||
public RichTextPropertyValueEditor(DataEditorAttribute attribute, IUmbracoContextAccessor umbracoContextAccessor, HtmlImageSourceParser imageSourceParser, HtmlLocalLinkParser localLinkParser, RichTextEditorPastedImages pastedImages)
|
||||
public RichTextPropertyValueEditor(DataEditorAttribute attribute, IUmbracoContextAccessor umbracoContextAccessor, HtmlImageSourceParser imageSourceParser, HtmlLocalLinkParser localLinkParser, RichTextEditorPastedImages pastedImages, IImageUrlGenerator imageUrlGenerator)
|
||||
: base(attribute)
|
||||
{
|
||||
_umbracoContextAccessor = umbracoContextAccessor;
|
||||
_imageSourceParser = imageSourceParser;
|
||||
_localLinkParser = localLinkParser;
|
||||
_pastedImages = pastedImages;
|
||||
_imageUrlGenerator = imageUrlGenerator;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -124,7 +138,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);
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ using Umbraco.Web.Trees;
|
||||
using Umbraco.Web.WebApi;
|
||||
using Current = Umbraco.Web.Composing.Current;
|
||||
using Umbraco.Web.PropertyEditors;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Models;
|
||||
|
||||
namespace Umbraco.Web.Runtime
|
||||
{
|
||||
@@ -190,6 +192,8 @@ namespace Umbraco.Web.Runtime
|
||||
composition.MediaUrlProviders()
|
||||
.Append<DefaultMediaUrlProvider>();
|
||||
|
||||
composition.RegisterUnique<IImageUrlGenerator, ImageProcessorImageUrlGenerator>();
|
||||
|
||||
composition.RegisterUnique<IContentLastChanceFinder, ContentFinderByConfigured404>();
|
||||
|
||||
composition.ContentFinders()
|
||||
|
||||
@@ -52,6 +52,6 @@ namespace Umbraco.Web.Templates
|
||||
|
||||
[Obsolete("Use " + nameof(HtmlImageSourceParser) + "." + nameof(RichTextEditorPastedImages.FindAndPersistPastedTempImages) + " instead")]
|
||||
internal static string FindAndPersistPastedTempImages(string html, Guid mediaParentFolder, int userId, IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, ILogger logger)
|
||||
=> Current.Factory.GetInstance<RichTextEditorPastedImages>().FindAndPersistPastedTempImages(html, mediaParentFolder, userId);
|
||||
=> Current.Factory.GetInstance<RichTextEditorPastedImages>().FindAndPersistPastedTempImages(html, mediaParentFolder, userId, Current.Factory.GetInstance<IImageUrlGenerator>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
<Compile Include="Editors\MacrosController.cs" />
|
||||
<Compile Include="Editors\RelationTypeController.cs" />
|
||||
<Compile Include="Editors\TinyMceController.cs" />
|
||||
<Compile Include="ImageCropperTemplateCoreExtensions.cs" />
|
||||
<Compile Include="IUmbracoContextFactory.cs" />
|
||||
<Compile Include="Install\ChangesMonitor.cs" />
|
||||
<Compile Include="Logging\WebProfiler.cs" />
|
||||
@@ -223,6 +224,7 @@
|
||||
<Compile Include="Models\ContentEditing\MacroDisplay.cs" />
|
||||
<Compile Include="Models\ContentEditing\MacroParameterDisplay.cs" />
|
||||
<Compile Include="Models\ContentEditing\UrlAndAnchors.cs" />
|
||||
<Compile Include="Models\ImageProcessorImageUrlGenerator.cs" />
|
||||
<Compile Include="Models\Mapping\CommonMapper.cs" />
|
||||
<Compile Include="Models\Mapping\MapperContextExtensions.cs" />
|
||||
<Compile Include="Models\PublishedContent\HybridVariationContextAccessor.cs" />
|
||||
|
||||
Reference in New Issue
Block a user