Merge remote-tracking branch 'origin/netcore/dev' into netcore/feature/AB4919-untable-umbraco-context

This commit is contained in:
Bjarke Berg
2020-02-13 09:50:19 +01:00
34 changed files with 1059 additions and 571 deletions

View File

@@ -0,0 +1,7 @@
namespace Umbraco.Core.Models
{
public interface IImageUrlGenerator
{
string GetImageUrl(ImageUrlGenerationOptions options);
}
}

View File

@@ -0,0 +1,66 @@
namespace Umbraco.Core.Models
{
/// <summary>
/// These are options that are passed to the IImageUrlGenerator implementation to determine
/// the propery URL that is needed
/// </summary>
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; }
/// <summary>
/// The focal point position, in whatever units the registered IImageUrlGenerator uses,
/// typically a percentage of the total image from 0.0 to 1.0.
/// </summary>
public class FocalPointPosition
{
public FocalPointPosition (decimal top, decimal left)
{
Left = left;
Top = top;
}
public decimal Left { get; }
public decimal Top { get; }
}
/// <summary>
/// The bounds of the crop within the original image, in whatever units the registered
/// IImageUrlGenerator uses, typically a percentage between 0 and 100.
/// </summary>
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; }
}
}
}

View File

@@ -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
/// <returns>
/// A list of 5 different sized avatar URLs
/// </returns>
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 })
};
}

View File

@@ -77,7 +77,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
public IEnumerable<IAuditItem> Get(AuditType type, IQuery<IAuditItem> query)
{
var sqlClause = GetBaseQuery(false)
.Where<LogDto>(x => x.Header == type.ToString());
.Where("(logHeader=@0)", type.ToString());
var translator = new SqlTranslator<IAuditItem>(sqlClause, query);
var sql = translator.Translate();

View File

@@ -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 };
}
}
/// <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)
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);
}
/// <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)
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>

View File

@@ -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<IAuditItem>();

View File

@@ -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);
}
/// <summary>
/// Test that if a crop alias has been specified that doesn't exist the method returns null
/// </summary>
[Test]
public void GetCropUrlNullTest()
{
var urlString = Generator.GetImageUrl(null);
Assert.AreEqual(null, urlString);
}
/// <summary>
/// Test that if a crop alias has been specified that doesn't exist the method returns null
/// </summary>
[Test]
public void GetCropUrlEmptyTest()
{
var urlString = Generator.GetImageUrl(new ImageUrlGenerationOptions(null));
Assert.AreEqual("?mode=crop", urlString);
}
/// <summary>
/// Test the GetCropUrl method on the ImageCropDataSet Model
/// </summary>
[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);
}
/// <summary>
/// Test the height ratio mode with predefined crop dimensions
/// </summary>
[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);
}
/// <summary>
/// Test the height ratio mode with manual width/height dimensions
/// </summary>
[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);
}
/// <summary>
/// Test the height ratio mode with width/height dimensions
/// </summary>
[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);
}
/// <summary>
/// Test that if Crop mode is specified as anything other than Crop the image doesn't use the crop
/// </summary>
[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);
}
/// <summary>
/// Test for upload property type
/// </summary>
[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);
}
/// <summary>
/// Test for preferFocalPoint when focal point is centered
/// </summary>
[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);
}
/// <summary>
/// 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
/// </summary>
[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);
}
/// <summary>
/// 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
/// </summary>
[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);
}
/// <summary>
/// Test to check if crop ratio is ignored if useCropDimensions is true
/// </summary>
[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);
}
/// <summary>
/// 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
/// </summary>
[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);
}
/// <summary>
/// Test to check result when only a width parameter is passed, effectivly a resize only
/// </summary>
[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);
}
/// <summary>
/// Test to check result when only a height parameter is passed, effectivly a resize only
/// </summary>
[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);
}
/// <summary>
/// Test to check result when using a background color with padding
/// </summary>
[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);
}
}
}

View File

@@ -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);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -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();
}
}
}
}

View File

@@ -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<IImageUrlGenerator>())) { Id = 1 });
var publishedContentTypeFactory = new PublishedContentTypeFactory(Mock.Of<IPublishedModelFactory>(), converters, dataTypeService);

View File

@@ -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<IDataTypeService>(), localizationService, LocalizedTextService, ShortStringHelper)) { Id = 1 },
new DataType(new TrueFalsePropertyEditor(logger, Mock.Of<IDataTypeService>(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService)) { Id = 1001 },
new DataType(new RichTextPropertyEditor(logger, mediaService, contentTypeBaseServiceProvider, umbracoContextAccessor, Mock.Of<IDataTypeService>(), localizationService, imageSourceParser, linkParser, pastedImages, ShortStringHelper, IOHelper, LocalizedTextService)) { Id = 1002 },
new DataType(new RichTextPropertyEditor(logger, mediaService, contentTypeBaseServiceProvider, umbracoContextAccessor, Mock.Of<IDataTypeService>(), localizationService, imageSourceParser, linkParser, pastedImages, ShortStringHelper, IOHelper, LocalizedTextService, Mock.Of<IImageUrlGenerator>())) { Id = 1002 },
new DataType(new IntegerPropertyEditor(logger, Mock.Of<IDataTypeService>(), localizationService, ShortStringHelper, LocalizedTextService)) { Id = 1003 },
new DataType(new TextboxPropertyEditor(logger, Mock.Of<IDataTypeService>(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService)) { Id = 1004 },
new DataType(new MediaPickerPropertyEditor(logger, Mock.Of<IDataTypeService>(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService)) { Id = 1005 });

View File

@@ -106,6 +106,7 @@ namespace Umbraco.Tests.Runtimes
composition.Register<IDefaultCultureAccessor, TestDefaultCultureAccessor>(Lifetime.Singleton);
composition.Register<ISiteDomainHelper>(_ => Mock.Of<ISiteDomainHelper>(), Lifetime.Singleton);
composition.RegisterUnique(f => new DistributedCache(f.GetInstance<IServerMessenger>(), f.GetInstance<CacheRefresherCollection>()));
composition.Register(_ => Mock.Of<IImageUrlGenerator>(), Lifetime.Singleton);
composition.WithCollectionBuilder<UrlProviderCollectionBuilder>().Append<DefaultUrlProvider>();
composition.RegisterUnique<IDistributedCacheBinder, DistributedCacheBinder>();
composition.RegisterUnique<IExamineManager, ExamineManager>();

View File

@@ -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<IRuntimeState>();
runtimeStateMock.Setup(x => x.Level).Returns(RuntimeLevel.Run);
Composition.RegisterUnique(f => runtimeStateMock.Object);
Composition.Register(_ => Mock.Of<IImageUrlGenerator>());
// ah...
Composition.WithCollectionBuilder<ActionCollectionBuilder>();

View File

@@ -142,6 +142,7 @@
<Compile Include="ModelsBuilder\UmbracoApplicationTests.cs" />
<Compile Include="Models\ContentScheduleTests.cs" />
<Compile Include="Models\CultureImpactTests.cs" />
<Compile Include="Models\ImageProcessorImageUrlGeneratorTest.cs" />
<Compile Include="Models\PathValidationTests.cs" />
<Compile Include="Models\VariationTests.cs" />
<Compile Include="Persistence\Mappers\MapperTestBase.cs" />

View File

@@ -90,7 +90,8 @@ namespace Umbraco.Tests.Web.Controllers
ShortStringHelper,
Factory.GetInstance<UmbracoMapper>(),
Factory.GetInstance<IUmbracoSettingsSection>(),
Factory.GetInstance<IIOHelper>()
Factory.GetInstance<IIOHelper>(),
Factory.GetInstance<IImageUrlGenerator>()
);
return usersController;
}
@@ -160,7 +161,8 @@ namespace Umbraco.Tests.Web.Controllers
ShortStringHelper,
Factory.GetInstance<UmbracoMapper>(),
Factory.GetInstance<IUmbracoSettingsSection>(),
Factory.GetInstance<IIOHelper>()
Factory.GetInstance<IIOHelper>(),
Factory.GetInstance<IImageUrlGenerator>()
);
return usersController;
}
@@ -201,7 +203,8 @@ namespace Umbraco.Tests.Web.Controllers
ShortStringHelper,
Factory.GetInstance<UmbracoMapper>(),
Factory.GetInstance<IUmbracoSettingsSection>(),
Factory.GetInstance<IIOHelper>()
Factory.GetInstance<IIOHelper>(),
Factory.GetInstance<IImageUrlGenerator>()
);
return usersController;
}
@@ -277,7 +280,8 @@ namespace Umbraco.Tests.Web.Controllers
ShortStringHelper,
Factory.GetInstance<UmbracoMapper>(),
Factory.GetInstance<IUmbracoSettingsSection>(),
Factory.GetInstance<IIOHelper>()
Factory.GetInstance<IIOHelper>(),
Factory.GetInstance<IImageUrlGenerator>()
);
return usersController;
}

View File

@@ -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);
})();

View File

@@ -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;
}
}

View File

@@ -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 @@
{
<div class="col-xs-6 col-md-3">
<a href="@item.Url()" class="thumbnail">
<img src="@item.GetCropUrl(width:200, height:200)" alt="@item.Name" />
<img src="@(item.GetCropUrl(Current.Factory.GetInstance<IImageUrlGenerator>(), width:200, height:200))" alt="@item.Name" />
</a>
</div>
}

View File

@@ -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 += "&center=" + Model.value.focalPoint.top +"," + Model.value.focalPoint.left;
url += "&mode=crop";
}
url = ImageCropperTemplateCoreExtensions.GetCropUrl(url, Umbraco.Web.Composing.Current.Factory.GetInstance<IImageUrlGenerator>(),
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)

View File

@@ -321,6 +321,10 @@ namespace Umbraco.Web.Editors
"tinyMceApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl<TinyMceController>(
controller => controller.UploadImage())
},
{
"imageUrlGeneratorApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl<ImageUrlGeneratorController>(
controller => controller.GetCropUrl(null, null, null, null, null))
},
}
},
{

View File

@@ -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;
}
/// <summary>
@@ -187,7 +191,7 @@ namespace Umbraco.Web.Editors
public async Task<HttpResponseMessage> 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));
}
/// <summary>

View File

@@ -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
{
/// <summary>
/// The API controller used for getting URLs for images with parameters
/// </summary>
/// <remarks>
/// <para>
/// 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
/// </para>
/// </remarks>
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);
}
}
}

View File

@@ -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;
}
/// <summary>
@@ -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;
}

View File

@@ -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)
{

View File

@@ -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;
}
/// <summary>
@@ -77,7 +80,7 @@ namespace Umbraco.Web.Editors
/// <returns></returns>
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<HttpResponseMessage> 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<HttpResponseMessage> PostSetAvatarInternal(HttpRequestMessage request, IUserService userService, IAppCache cache, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, IUmbracoSettingsSection umbracoSettingsSection, IIOHelper ioHelper, int id)
internal static async Task<HttpResponseMessage> 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));
}
/// <summary>

View File

@@ -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
{
/// <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,
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);
}
}
}

View File

@@ -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
/// </summary>
public static class ImageCropperTemplateExtensions
{
/// <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)
{
return mediaItem.GetCropUrl(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)
{
return mediaItem.GetCropUrl(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,
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<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);
}
/// <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,
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);
}
/// <summary>
/// Gets the ImageProcessor Url from the image path.
/// </summary>
/// <param name="imageUrl">
/// The image url.
/// </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,
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();

View File

@@ -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");
}
}
}

View File

@@ -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();

View File

@@ -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
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
@@ -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;

View File

@@ -43,7 +43,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
@@ -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);

View File

@@ -33,6 +33,7 @@ namespace Umbraco.Web.PropertyEditors
private readonly HtmlLocalLinkParser _localLinkParser;
private readonly RichTextEditorPastedImages _pastedImages;
private readonly IIOHelper _ioHelper;
private readonly IImageUrlGenerator _imageUrlGenerator;
/// <summary>
/// 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;
}
/// <summary>
/// Create a custom value editor
/// </summary>
/// <returns></returns>
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;
}
/// <inheritdoc />
@@ -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);

View File

@@ -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<DefaultMediaUrlProvider>();
composition.RegisterUnique<IImageUrlGenerator, ImageProcessorImageUrlGenerator>();
composition.RegisterUnique<IContentLastChanceFinder, ContentFinderByConfigured404>();
composition.ContentFinders()

View File

@@ -148,6 +148,7 @@
<Compile Include="Editors\BackOfficePreviewModel.cs" />
<Compile Include="Editors\Filters\ContentSaveModelValidator.cs" />
<Compile Include="Editors\Filters\MediaSaveModelValidator.cs" />
<Compile Include="Editors\ImageUrlGeneratorController.cs" />
<Compile Include="Editors\PackageController.cs" />
<Compile Include="Editors\KeepAliveController.cs" />
<Compile Include="Editors\MacrosController.cs" />
@@ -156,6 +157,7 @@
<Compile Include="FrameworkMarchal.cs" />
<Compile Include="Hosting\AspNetHostingEnvironment.cs" />
<Compile Include="HttpContextExtensions.cs" />
<Compile Include="ImageCropperTemplateCoreExtensions.cs" />
<Compile Include="IUmbracoContextFactory.cs" />
<Compile Include="Install\ChangesMonitor.cs" />
<Compile Include="Logging\OwinLogger.cs" />
@@ -172,6 +174,7 @@
<Compile Include="Models\Identity\IdentityMapDefinition.cs" />
<Compile Include="Models\Identity\IdentityUser.cs" />
<Compile Include="Models\Identity\UserLoginInfoWrapper.cs" />
<Compile Include="Models\ImageProcessorImageUrlGenerator.cs" />
<Compile Include="Models\Mapping\CommonMapper.cs" />
<Compile Include="Models\Mapping\ContentMapDefinition.cs" />
<Compile Include="Models\Mapping\ContentPropertyBasicMapper.cs" />

View File

@@ -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.
/// </param>
/// <returns></returns>
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
/// <returns>
/// The ImageProcessor.Web Url.
/// </returns>
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
/// </returns>
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
/// </returns>
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);