From b67c3dfa04e7568629e0bc69b99be0f37d8e3472 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Tue, 24 Mar 2020 09:37:46 +0100 Subject: [PATCH 1/6] Moved IImageUrlGenerator and implementation into more appropriate enamespace --- src/Umbraco.Core/{Models => Media}/IImageUrlGenerator.cs | 4 +++- .../{Models => Media}/ImageProcessorImageUrlGenerator.cs | 3 ++- .../Models/Mapping/UserMapDefinition.cs | 1 + src/Umbraco.Infrastructure/Models/UserExtensions.cs | 1 + .../PropertyEditors/GridPropertyEditor.cs | 1 + .../PropertyEditors/RichTextEditorPastedImages.cs | 1 + .../PropertyEditors/RichTextPropertyEditor.cs | 1 + .../PropertyEditors/ValueConverters/ImageCropperValue.cs | 1 + .../Models/ImageProcessorImageUrlGeneratorTest.cs | 2 +- src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs | 1 + .../PublishedContent/PublishedContentTestBase.cs | 1 + src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs | 1 + src/Umbraco.Tests/Runtimes/StandaloneTests.cs | 1 + src/Umbraco.Tests/Testing/UmbracoTestBase.cs | 2 +- src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs | 1 + src/Umbraco.Web/Editors/CurrentUserController.cs | 2 +- src/Umbraco.Web/Editors/ImageUrlGeneratorController.cs | 2 +- src/Umbraco.Web/Editors/ImagesController.cs | 1 + src/Umbraco.Web/Editors/LogController.cs | 1 + src/Umbraco.Web/Editors/UsersController.cs | 1 + src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs | 1 + src/Umbraco.Web/Runtime/WebInitialComposer.cs | 4 ++-- src/Umbraco.Web/UrlHelperRenderExtensions.cs | 2 +- 23 files changed, 27 insertions(+), 9 deletions(-) rename src/Umbraco.Core/{Models => Media}/IImageUrlGenerator.cs (66%) rename src/Umbraco.Infrastructure/{Models => Media}/ImageProcessorImageUrlGenerator.cs (98%) diff --git a/src/Umbraco.Core/Models/IImageUrlGenerator.cs b/src/Umbraco.Core/Media/IImageUrlGenerator.cs similarity index 66% rename from src/Umbraco.Core/Models/IImageUrlGenerator.cs rename to src/Umbraco.Core/Media/IImageUrlGenerator.cs index 0dc2933fd9..f9e67cdd2b 100644 --- a/src/Umbraco.Core/Models/IImageUrlGenerator.cs +++ b/src/Umbraco.Core/Media/IImageUrlGenerator.cs @@ -1,4 +1,6 @@ -namespace Umbraco.Core.Models +using Umbraco.Core.Models; + +namespace Umbraco.Core.Media { public interface IImageUrlGenerator { diff --git a/src/Umbraco.Infrastructure/Models/ImageProcessorImageUrlGenerator.cs b/src/Umbraco.Infrastructure/Media/ImageProcessorImageUrlGenerator.cs similarity index 98% rename from src/Umbraco.Infrastructure/Models/ImageProcessorImageUrlGenerator.cs rename to src/Umbraco.Infrastructure/Media/ImageProcessorImageUrlGenerator.cs index f88309d7e3..61a12bedf6 100644 --- a/src/Umbraco.Infrastructure/Models/ImageProcessorImageUrlGenerator.cs +++ b/src/Umbraco.Infrastructure/Media/ImageProcessorImageUrlGenerator.cs @@ -1,9 +1,10 @@ using System.Globalization; using System.Text; using Umbraco.Core; +using Umbraco.Core.Media; using Umbraco.Core.Models; -namespace Umbraco.Web.Models +namespace Umbraco.Infrastructure.Media { public class ImageProcessorImageUrlGenerator : IImageUrlGenerator { diff --git a/src/Umbraco.Infrastructure/Models/Mapping/UserMapDefinition.cs b/src/Umbraco.Infrastructure/Models/Mapping/UserMapDefinition.cs index 19a78bcbe4..80f3a8bde8 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/UserMapDefinition.cs +++ b/src/Umbraco.Infrastructure/Models/Mapping/UserMapDefinition.cs @@ -16,6 +16,7 @@ using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.Actions; using Umbraco.Web.Services; +using Umbraco.Core.Media; namespace Umbraco.Web.Models.Mapping { diff --git a/src/Umbraco.Infrastructure/Models/UserExtensions.cs b/src/Umbraco.Infrastructure/Models/UserExtensions.cs index 0c0e4fbc48..4fefc89d11 100644 --- a/src/Umbraco.Infrastructure/Models/UserExtensions.cs +++ b/src/Umbraco.Infrastructure/Models/UserExtensions.cs @@ -9,6 +9,7 @@ using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; using Umbraco.Core.Security; +using Umbraco.Core.Media; namespace Umbraco.Core.Models { diff --git a/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyEditor.cs index 72e0843240..1a8e4524c7 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyEditor.cs @@ -5,6 +5,7 @@ using Newtonsoft.Json; using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.Logging; +using Umbraco.Core.Media; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs b/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs index eee45a636c..38b4611c1e 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs @@ -6,6 +6,7 @@ using Umbraco.Core; using Umbraco.Core.Exceptions; using Umbraco.Core.IO; using Umbraco.Core.Logging; +using Umbraco.Core.Media; using Umbraco.Core.Models; using Umbraco.Core.Services; using Umbraco.Core.Strings; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs index dea9a5f002..2f283b2709 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.Logging; +using Umbraco.Core.Media; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValue.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValue.cs index 1367c04cdb..5878e51dcd 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValue.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValue.cs @@ -4,6 +4,7 @@ using System.ComponentModel; using System.Linq; using System.Runtime.Serialization; using Newtonsoft.Json; +using Umbraco.Core.Media; using Umbraco.Core.Models; using Umbraco.Core.Serialization; using Umbraco.Core.Strings; diff --git a/src/Umbraco.Tests/Models/ImageProcessorImageUrlGeneratorTest.cs b/src/Umbraco.Tests/Models/ImageProcessorImageUrlGeneratorTest.cs index 30ead90de9..bf6529f45e 100644 --- a/src/Umbraco.Tests/Models/ImageProcessorImageUrlGeneratorTest.cs +++ b/src/Umbraco.Tests/Models/ImageProcessorImageUrlGeneratorTest.cs @@ -16,10 +16,10 @@ 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; +using Umbraco.Infrastructure.Media; namespace Umbraco.Tests.Models { diff --git a/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs b/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs index 919386f491..788b5dce10 100644 --- a/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs +++ b/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs @@ -23,6 +23,7 @@ using Umbraco.Web.PropertyEditors; using System.Text; using Current = Umbraco.Web.Composing.Current; using Umbraco.Core.Cache; +using Umbraco.Core.Media; namespace Umbraco.Tests.PropertyEditors { diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs index d99fc90813..3655a44d0d 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs @@ -16,6 +16,7 @@ using Umbraco.Web; using Umbraco.Web.Templates; using Umbraco.Web.Models; using Umbraco.Web.Routing; +using Umbraco.Core.Media; namespace Umbraco.Tests.PublishedContent { diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index e852c22828..2667848c57 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -25,6 +25,7 @@ using Umbraco.Web.Templates; using Umbraco.Web.Models; using Umbraco.Web.Routing; using Current = Umbraco.Web.Composing.Current; +using Umbraco.Core.Media; namespace Umbraco.Tests.PublishedContent { diff --git a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs index 0cb3f3e2e1..eee60ffc1a 100644 --- a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs +++ b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs @@ -36,6 +36,7 @@ using File = System.IO.File; using Current = Umbraco.Web.Composing.Current; using Umbraco.Tests.Common; using Umbraco.Tests.Common.Composing; +using Umbraco.Core.Media; namespace Umbraco.Tests.Runtimes { diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index ca36a6049e..bb6442b4d8 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -50,7 +50,6 @@ 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.Request; using Umbraco.Core.Security; using Umbraco.Core.Services; @@ -63,6 +62,7 @@ using Umbraco.Web.Security.Providers; using Umbraco.Web.Trees; using Current = Umbraco.Web.Composing.Current; using Umbraco.Tests.Common; +using Umbraco.Core.Media; namespace Umbraco.Tests.Testing { diff --git a/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs b/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs index 14bbc5f1fb..d6c9385aa9 100644 --- a/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs @@ -37,6 +37,7 @@ using IUser = Umbraco.Core.Models.Membership.IUser; using Umbraco.Core.Mapping; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Web.Routing; +using Umbraco.Core.Media; namespace Umbraco.Tests.Web.Controllers { diff --git a/src/Umbraco.Web/Editors/CurrentUserController.cs b/src/Umbraco.Web/Editors/CurrentUserController.cs index 384270743c..0b288735fe 100644 --- a/src/Umbraco.Web/Editors/CurrentUserController.cs +++ b/src/Umbraco.Web/Editors/CurrentUserController.cs @@ -22,8 +22,8 @@ using Umbraco.Web.Security; using Umbraco.Web.WebApi.Filters; using Umbraco.Core.Mapping; using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Models; using Umbraco.Web.Routing; +using Umbraco.Core.Media; namespace Umbraco.Web.Editors { diff --git a/src/Umbraco.Web/Editors/ImageUrlGeneratorController.cs b/src/Umbraco.Web/Editors/ImageUrlGeneratorController.cs index 87d7e29619..e5369fb7a1 100644 --- a/src/Umbraco.Web/Editors/ImageUrlGeneratorController.cs +++ b/src/Umbraco.Web/Editors/ImageUrlGeneratorController.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Umbraco.Core.Models; +using Umbraco.Core.Media; using Umbraco.Web.Models; using Umbraco.Web.Mvc; diff --git a/src/Umbraco.Web/Editors/ImagesController.cs b/src/Umbraco.Web/Editors/ImagesController.cs index 39fe619b9d..515b5e9c8c 100644 --- a/src/Umbraco.Web/Editors/ImagesController.cs +++ b/src/Umbraco.Web/Editors/ImagesController.cs @@ -4,6 +4,7 @@ using System.Net; using System.Net.Http; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.IO; +using Umbraco.Core.Media; using Umbraco.Core.Models; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; diff --git a/src/Umbraco.Web/Editors/LogController.cs b/src/Umbraco.Web/Editors/LogController.cs index b502802775..7d69a4169c 100644 --- a/src/Umbraco.Web/Editors/LogController.cs +++ b/src/Umbraco.Web/Editors/LogController.cs @@ -7,6 +7,7 @@ using Umbraco.Core.Configuration; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Mapping; +using Umbraco.Core.Media; using Umbraco.Core.Models; using Umbraco.Core.Persistence; using Umbraco.Core.Services; diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs index 9554906b0d..eec10be1ac 100644 --- a/src/Umbraco.Web/Editors/UsersController.cs +++ b/src/Umbraco.Web/Editors/UsersController.cs @@ -36,6 +36,7 @@ using Task = System.Threading.Tasks.Task; using Umbraco.Core.Mapping; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Web.Routing; +using Umbraco.Core.Media; namespace Umbraco.Web.Editors { diff --git a/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs b/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs index 7ac5578d75..68bbb26784 100644 --- a/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs +++ b/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs @@ -6,6 +6,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors.ValueConverters; using Umbraco.Web.Models; +using Umbraco.Core.Media; namespace Umbraco.Web { diff --git a/src/Umbraco.Web/Runtime/WebInitialComposer.cs b/src/Umbraco.Web/Runtime/WebInitialComposer.cs index b81cafdb40..edaa0dbd16 100644 --- a/src/Umbraco.Web/Runtime/WebInitialComposer.cs +++ b/src/Umbraco.Web/Runtime/WebInitialComposer.cs @@ -45,11 +45,11 @@ using Umbraco.Web.Trees; using Umbraco.Web.WebApi; using Umbraco.Web.PropertyEditors; using Umbraco.Examine; -using Umbraco.Core.Models; using Umbraco.Core.Request; using Umbraco.Core.Session; using Umbraco.Web.AspNet; -using Umbraco.Web.Models; +using Umbraco.Core.Media; +using Umbraco.Infrastructure.Media; namespace Umbraco.Web.Runtime { diff --git a/src/Umbraco.Web/UrlHelperRenderExtensions.cs b/src/Umbraco.Web/UrlHelperRenderExtensions.cs index 0cf009cb88..156a3dfba1 100644 --- a/src/Umbraco.Web/UrlHelperRenderExtensions.cs +++ b/src/Umbraco.Web/UrlHelperRenderExtensions.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Web; using System.Web.Mvc; using Umbraco.Core; -using Umbraco.Core.Models; +using Umbraco.Core.Media; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors.ValueConverters; using Umbraco.Web.Composing; From c16965319a90d63fb3e674299c6cd535740b89cd Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Tue, 24 Mar 2020 12:17:41 +0100 Subject: [PATCH 2/6] Amended processed image URL building to use checks for empty as well as null, and refactored null checks to use HasValue. --- .../Media/ImageProcessorImageUrlGenerator.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Infrastructure/Media/ImageProcessorImageUrlGenerator.cs b/src/Umbraco.Infrastructure/Media/ImageProcessorImageUrlGenerator.cs index 61a12bedf6..f1a0121653 100644 --- a/src/Umbraco.Infrastructure/Media/ImageProcessorImageUrlGenerator.cs +++ b/src/Umbraco.Infrastructure/Media/ImageProcessorImageUrlGenerator.cs @@ -28,18 +28,18 @@ namespace Umbraco.Infrastructure.Media //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.Quality.HasValue && hasFormat == false) imageProcessorUrl.Append("&quality=").Append(options.Quality); + if (options.HeightRatio.HasValue) imageProcessorUrl.Append("&heightratio=").Append(options.HeightRatio.Value.ToString(CultureInfo.InvariantCulture)); + if (options.WidthRatio.HasValue) imageProcessorUrl.Append("&widthratio=").Append(options.WidthRatio.Value.ToString(CultureInfo.InvariantCulture)); + if (options.Width.HasValue) imageProcessorUrl.Append("&width=").Append(options.Width); + if (options.Height.HasValue) 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 (!string.IsNullOrWhiteSpace(options.AnimationProcessMode)) imageProcessorUrl.Append("&animationprocessmode=").Append(options.AnimationProcessMode); + if (!string.IsNullOrWhiteSpace(options.FurtherOptions)) 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); + if (options.Quality.HasValue && hasFormat) imageProcessorUrl.Append("&quality=").Append(options.Quality); + if (!string.IsNullOrWhiteSpace(options.CacheBusterValue)) imageProcessorUrl.Append("&rnd=").Append(options.CacheBusterValue); return imageProcessorUrl.ToString(); } From e66c92d032ed0de41fc548e425526b48d498e7c6 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Tue, 24 Mar 2020 12:19:04 +0100 Subject: [PATCH 3/6] Added controller method to ImagesController and client-side method to mediahelper to retrieve URL for processed image. --- .../common/services/mediahelper.service.js | 53 ++++++++++++++++--- src/Umbraco.Web/Editors/ImagesController.cs | 41 ++++++++++++++ 2 files changed, 88 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js index 2271f891ce..953ddf46d9 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js @@ -3,7 +3,7 @@ * @name umbraco.services.mediaHelper * @description A helper object used for dealing with media items **/ -function mediaHelper(umbRequestHelper, $log) { +function mediaHelper(umbRequestHelper, $http, $log) { //container of fileresolvers var _mediaFileResolvers = {}; @@ -304,11 +304,6 @@ function mediaHelper(umbRequestHelper, $log) { return imagePath; } - // Check if file is a svg - if (this.getFileExtension(imagePath) === "svg") { - return imagePath; - } - // If the path is not an image we cannot get a thumb if (!this.detectIfImageByExtension(imagePath)) { return null; @@ -399,6 +394,52 @@ function mediaHelper(umbRequestHelper, $log) { var lowered = filePath.toLowerCase(); var ext = lowered.substr(lowered.lastIndexOf(".") + 1); return ext; + }, + + /** + * @ngdoc function + * @name umbraco.services.mediaHelper#getProcessedImageUrl + * @methodOf umbraco.services.mediaHelper + * @function + * + * @description + * Returns image URL with configured crop and other processing parameters. + * + * @param {string} imagePath Raw image path + * @param {object} options Object describing image generation parameters: + * { + * animationProcessMode: + * focalPoint: { + * left: + * top: + * }, + * height: + * mode: + * upscale: + * width: + * } + */ + getProcessedImageUrl: function (imagePath, options) { + + if (!options) { + return imagePath; + } + + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "imagesApiBaseUrl", + "GetProcessedImageUrl", + { + imagePath, + animationProcessMode: options.animationProcessMode, + focalPoint: options.focalPoint, + height: options.height, + mode: options.mode, + upscale: options.upscale || false, + width: options.width + })), + "Failed to retrieve processed image URL for image: " + imagePath); } }; diff --git a/src/Umbraco.Web/Editors/ImagesController.cs b/src/Umbraco.Web/Editors/ImagesController.cs index 515b5e9c8c..960b589b6d 100644 --- a/src/Umbraco.Web/Editors/ImagesController.cs +++ b/src/Umbraco.Web/Editors/ImagesController.cs @@ -84,5 +84,46 @@ namespace Umbraco.Web.Editors return response; } + /// + /// Gets a processed image for the image at the given path + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// If there is no media, image property or image file is found then this will return not found. + /// + public string GetProcessedImageUrl(string imagePath, + int? width = null, + int? height = null, + int? focalPointLeft = null, + int? focalPointTop = null, + string animationProcessMode = "first", + string mode = "crop", + bool upscale = false, + string cacheBusterValue = "") +{ + var options = new ImageUrlGenerationOptions(imagePath) + { + AnimationProcessMode = "first", + CacheBusterValue = cacheBusterValue, + Height = height, + ImageCropMode = "max", + UpScale = false, + Width = width, + }; + if (focalPointLeft.HasValue && focalPointTop.HasValue) + { + options.FocalPoint = new ImageUrlGenerationOptions.FocalPointPosition(focalPointTop.Value, focalPointLeft.Value); + } + + return _imageUrlGenerator.GetImageUrl(options); + } } } From 519fd22cea52fc16786f9fc202b891a2b573bf7d Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Tue, 24 Mar 2020 12:29:16 +0100 Subject: [PATCH 4/6] Changed hard-coded processed images URLs in back-office to use configured image URL generation. --- .../common/services/mediahelper.service.js | 2 + .../src/common/services/tinymce.service.js | 26 ++- .../fileupload/fileupload.controller.js | 17 +- .../grid/editors/media.controller.js | 161 +++++++++--------- .../imagecropper/imagecropper.controller.js | 12 +- src/Umbraco.Web/Editors/ImagesController.cs | 8 +- 6 files changed, 131 insertions(+), 95 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js index 953ddf46d9..244573d79c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/mediahelper.service.js @@ -409,6 +409,7 @@ function mediaHelper(umbRequestHelper, $http, $log) { * @param {object} options Object describing image generation parameters: * { * animationProcessMode: + * cacheBusterValue: * focalPoint: { * left: * top: @@ -433,6 +434,7 @@ function mediaHelper(umbRequestHelper, $http, $log) { { imagePath, animationProcessMode: options.animationProcessMode, + cacheBusterValue: options.cacheBusterValue, focalPoint: options.focalPoint, height: options.height, mode: options.mode, diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js index d2b91a3707..957308a111 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js @@ -7,7 +7,7 @@ * A service containing all logic for all of the Umbraco TinyMCE plugins */ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, stylesheetResource, macroResource, macroService, - $routeParams, umbRequestHelper, angularHelper, userService, editorService, entityResource, eventsService, localStorageService) { + $routeParams, umbRequestHelper, angularHelper, userService, editorService, entityResource, eventsService, localStorageService, mediaHelper) { //These are absolutely required in order for the macros to render inline //we put these as extended elements because they get merged on top of the normal allowed elements by tiny mce @@ -298,15 +298,20 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s if (editor.settings.maxImageSize && editor.settings.maxImageSize !== 0) { var newSize = imageHelper.scaleToMaxSize(editor.settings.maxImageSize, size.w, size.h); - editor.dom.setAttrib(imageDomElement, 'width', newSize.width); editor.dom.setAttrib(imageDomElement, 'height', newSize.height); // Images inserted via Media Picker will have a URL we can use for ImageResizer QueryStrings // Images pasted/dragged in are not persisted to media until saved & thus will need to be added - if(imgUrl){ - var src = imgUrl + "?width=" + newSize.width + "&height=" + newSize.height; - editor.dom.setAttrib(imageDomElement, 'data-mce-src', src); + if (imgUrl) { + mediaHelper.getProcessedImageUrl(imgUrl, + { + height: newSize.height, + width: newSize.width + }) + .then(function (resizedImgUrl) { + editor.dom.setAttrib(imageDomElement, 'data-mce-src', resizedImgUrl); + }); } editor.execCommand("mceAutoResize", false, null, null); @@ -1495,10 +1500,17 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s }); args.editor.on('ObjectResized', function (e) { - var qs = "?width=" + e.width + "&height=" + e.height + "&mode=max"; var srcAttr = $(e.target).attr("src"); var path = srcAttr.split("?")[0]; - $(e.target).attr("data-mce-src", path + qs); + mediaHelper.getProcessedImageUrl(path, + { + height: e.height, + moded: "max", + width: e.width + }) + .then(function (resizedPath) { + $(e.target).attr("data-mce-src", resizedPath); + }); syncContent(); }); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js index 17959b9950..ee71a0d2f2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js @@ -44,15 +44,22 @@ .controller('Umbraco.PropertyEditors.FileUploadController', fileUploadController) .run(function (mediaHelper, umbRequestHelper, assetsService) { if (mediaHelper && mediaHelper.registerFileResolver) { - - //NOTE: The 'entity' can be either a normal media entity or an "entity" returned from the entityResource + // NOTE: The 'entity' can be either a normal media entity or an "entity" returned from the entityResource // they contain different data structures so if we need to query against it we need to be aware of this. mediaHelper.registerFileResolver("Umbraco.UploadField", function (property, entity, thumbnail) { if (thumbnail) { if (mediaHelper.detectIfImageByExtension(property.value)) { - //get default big thumbnail from image processor - var thumbnailUrl = property.value + "?rnd=" + moment(entity.updateDate).format("YYYYMMDDHHmmss") + "&width=500&animationprocessmode=first"; - return thumbnailUrl; + + // Get default big thumbnail from image processor + return mediaHelper.getProcessedImageUrl(property.value, + { + animationprocessmode: "first", + cacheBusterValue: moment(entity.updateDate).format("YYYYMMDDHHmmss"), + width: 500 + }) + .then(function (url) { + return url; + }); } else { return null; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js index 574aa87557..1fb8cbe2f2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js @@ -1,90 +1,97 @@ angular.module("umbraco") .controller("Umbraco.PropertyEditors.Grid.MediaController", - function ($scope, $timeout, userService, editorService) { - - - $scope.thumbnailUrl = getThumbnailUrl(); - - - if (!$scope.model.config.startNodeId) { - if ($scope.model.config.ignoreUserStartNodes === true) { - $scope.model.config.startNodeId = -1; - $scope.model.config.startNodeIsVirtual = true; + function ($scope, userService, editorService, mediaHelper) { - } else { - userService.getCurrentUser().then(function (userData) { - $scope.model.config.startNodeId = userData.startMediaIds.length !== 1 ? -1 : userData.startMediaIds[0]; - $scope.model.config.startNodeIsVirtual = userData.startMediaIds.length !== 1; - }); - } - } - - $scope.setImage = function(){ - var startNodeId = $scope.model.config && $scope.model.config.startNodeId ? $scope.model.config.startNodeId : undefined; - var startNodeIsVirtual = startNodeId ? $scope.model.config.startNodeIsVirtual : undefined; + $scope.thumbnailUrl = getThumbnailUrl(); - var mediaPicker = { - startNodeId: startNodeId, - startNodeIsVirtual: startNodeIsVirtual, - cropSize: $scope.control.editor.config && $scope.control.editor.config.size ? $scope.control.editor.config.size : undefined, - showDetails: true, - disableFolderSelect: true, - onlyImages: true, - dataTypeKey: $scope.model.dataTypeKey, - submit: function(model) { - var selectedImage = model.selection[0]; - - $scope.control.value = { - focalPoint: selectedImage.focalPoint, - id: selectedImage.id, - udi: selectedImage.udi, - image: selectedImage.image, - caption: selectedImage.altText - }; - - editorService.close(); - }, - close: function() { - editorService.close(); + if (!$scope.model.config.startNodeId) { + if ($scope.model.config.ignoreUserStartNodes === true) { + $scope.model.config.startNodeId = -1; + $scope.model.config.startNodeIsVirtual = true; + + } else { + userService.getCurrentUser().then(function (userData) { + $scope.model.config.startNodeId = userData.startMediaIds.length !== 1 ? -1 : userData.startMediaIds[0]; + $scope.model.config.startNodeIsVirtual = userData.startMediaIds.length !== 1; + }); } } - - editorService.mediaPicker(mediaPicker); - }; - - $scope.$watch('control.value', function(newValue, oldValue) { - if(angular.equals(newValue, oldValue)){ - return; // simply skip that - } - - $scope.thumbnailUrl = getThumbnailUrl(); - }, true); - - function getThumbnailUrl() { - if($scope.control.value && $scope.control.value.image) { - var url = $scope.control.value.image; + $scope.setImage = function () { + var startNodeId = $scope.model.config && $scope.model.config.startNodeId ? $scope.model.config.startNodeId : undefined; + var startNodeIsVirtual = startNodeId ? $scope.model.config.startNodeIsVirtual : undefined; - if($scope.control.editor.config && $scope.control.editor.config.size){ - url += "?width=" + $scope.control.editor.config.size.width; - url += "&height=" + $scope.control.editor.config.size.height; - url += "&animationprocessmode=first"; + var mediaPicker = { + startNodeId: startNodeId, + startNodeIsVirtual: startNodeIsVirtual, + cropSize: $scope.control.editor.config && $scope.control.editor.config.size ? $scope.control.editor.config.size : undefined, + showDetails: true, + disableFolderSelect: true, + onlyImages: true, + dataTypeKey: $scope.model.dataTypeKey, + submit: function (model) { + var selectedImage = model.selection[0]; - if($scope.control.value.focalPoint){ - url += "¢er=" + $scope.control.value.focalPoint.top +"," + $scope.control.value.focalPoint.left; - url += "&mode=crop"; + $scope.control.value = { + focalPoint: selectedImage.focalPoint, + id: selectedImage.id, + udi: selectedImage.udi, + image: selectedImage.image, + caption: selectedImage.altText + }; + + editorService.close(); + }, + close: function () { + editorService.close(); } } - // set default size if no crop present (moved from the view) - if (url.indexOf('?') == -1) - { - url += "?width=800&upscale=false&animationprocessmode=false" - } - return url; - } - - return null; - }; + editorService.mediaPicker(mediaPicker); + }; -}); + $scope.$watch('control.value', function (newValue, oldValue) { + if (angular.equals(newValue, oldValue)) { + return; // simply skip that + } + + $scope.thumbnailUrl = getThumbnailUrl(); + }, true); + + function getThumbnailUrl() { + if ($scope.control.value && $scope.control.value.image) { + + var imageOptions; + if (url.indexOf('?') == -1) { + // set default size if no crop present (moved from the view) + imageOptions = { + animationprocessmode : false, + width: 800 + } + } + else { + imageOptions = { + animationprocessmode: "first", + height: $scope.control.editor.config.size.height, + width: $scope.control.editor.config.size.width + }; + + if ($scope.control.value.focalPoint) { + imageOptions.focalPoint = { + left: $scope.control.value.focalPoint.left, + top: $scope.control.value.focalPoint.top + } + imageOptions.mode = "crop"; + } + } + + return mediaHelper.getProcessedImageUrl($scope.control.value.image, imageOptions) + .then(function (url) { + return url; + }); + } + + return null; + }; + + }); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.controller.js index e3576426a3..c483e83845 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.controller.js @@ -222,9 +222,17 @@ angular.module('umbraco') // they contain different data structures so if we need to query against it we need to be aware of this. mediaHelper.registerFileResolver("Umbraco.ImageCropper", function (property, entity, thumbnail) { if (property.value && property.value.src) { - if (thumbnail === true) { - return property.value.src + "?width=500&mode=max&animationprocessmode=first"; + return mediaHelper.getProcessedImageUrl(property.value.src, + { + animationprocessmode: "first", + mode: "max", + width: 500 + }) + .then(function (url) { + return url; + }); + } else { return property.value.src; diff --git a/src/Umbraco.Web/Editors/ImagesController.cs b/src/Umbraco.Web/Editors/ImagesController.cs index 960b589b6d..bbad627c3b 100644 --- a/src/Umbraco.Web/Editors/ImagesController.cs +++ b/src/Umbraco.Web/Editors/ImagesController.cs @@ -105,17 +105,17 @@ namespace Umbraco.Web.Editors int? focalPointLeft = null, int? focalPointTop = null, string animationProcessMode = "first", - string mode = "crop", + string mode = "max", bool upscale = false, string cacheBusterValue = "") { var options = new ImageUrlGenerationOptions(imagePath) { - AnimationProcessMode = "first", + AnimationProcessMode = animationProcessMode, CacheBusterValue = cacheBusterValue, Height = height, - ImageCropMode = "max", - UpScale = false, + ImageCropMode = mode, + UpScale = upscale, Width = width, }; if (focalPointLeft.HasValue && focalPointTop.HasValue) From 93fd2eb954a5bb8ba49ea91e80d75c07e9b690d2 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Sat, 28 Mar 2020 13:59:52 +0100 Subject: [PATCH 5/6] Fixed creation of image processing options in grid media controller. --- .../grid/editors/media.controller.js | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js index 1fb8cbe2f2..7c98fbfc5e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js @@ -2,7 +2,7 @@ angular.module("umbraco") .controller("Umbraco.PropertyEditors.Grid.MediaController", function ($scope, userService, editorService, mediaHelper) { - $scope.thumbnailUrl = getThumbnailUrl(); + setThumbnailUrl(); if (!$scope.model.config.startNodeId) { if ($scope.model.config.ignoreUserStartNodes === true) { @@ -55,26 +55,24 @@ angular.module("umbraco") return; // simply skip that } - $scope.thumbnailUrl = getThumbnailUrl(); + setThumbnailUrl(); }, true); - function getThumbnailUrl() { + function setThumbnailUrl() { if ($scope.control.value && $scope.control.value.image) { - - var imageOptions; + var url = $scope.control.value.image; + var imageOptions = {}; if (url.indexOf('?') == -1) { // set default size if no crop present (moved from the view) - imageOptions = { - animationprocessmode : false, - width: 800 - } + imageOptions.animationprocessmode = false; + imageOptions.width = 800; } else { - imageOptions = { - animationprocessmode: "first", - height: $scope.control.editor.config.size.height, - width: $scope.control.editor.config.size.width - }; + if ($scope.control.editor.config && $scope.control.editor.config.size) { + imageOptions.animationprocessmode = "first"; + imageOptions.height = $scope.control.editor.config.size.height; + imageOptions.width = $scope.control.editor.config.size.width; + } if ($scope.control.value.focalPoint) { imageOptions.focalPoint = { @@ -85,13 +83,11 @@ angular.module("umbraco") } } - return mediaHelper.getProcessedImageUrl($scope.control.value.image, imageOptions) + mediaHelper.getProcessedImageUrl($scope.control.value.image, imageOptions) .then(function (url) { - return url; + $scope.thumbnailUrl = url; }); } - - return null; }; }); From 75b216bca569ed4d9498dac2fd39d801870d54e5 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Mon, 30 Mar 2020 14:30:50 +0200 Subject: [PATCH 6/6] Removed registerFileResolver methods on image cropper and file upload property editors. --- .../fileupload/fileupload.controller.js | 34 +------------ .../imagecropper/imagecropper.controller.js | 51 ------------------- 2 files changed, 1 insertion(+), 84 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js index ee71a0d2f2..15f8dbf11c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js @@ -41,37 +41,5 @@ }; angular.module("umbraco") - .controller('Umbraco.PropertyEditors.FileUploadController', fileUploadController) - .run(function (mediaHelper, umbRequestHelper, assetsService) { - if (mediaHelper && mediaHelper.registerFileResolver) { - // NOTE: The 'entity' can be either a normal media entity or an "entity" returned from the entityResource - // they contain different data structures so if we need to query against it we need to be aware of this. - mediaHelper.registerFileResolver("Umbraco.UploadField", function (property, entity, thumbnail) { - if (thumbnail) { - if (mediaHelper.detectIfImageByExtension(property.value)) { - - // Get default big thumbnail from image processor - return mediaHelper.getProcessedImageUrl(property.value, - { - animationprocessmode: "first", - cacheBusterValue: moment(entity.updateDate).format("YYYYMMDDHHmmss"), - width: 500 - }) - .then(function (url) { - return url; - }); - } - else { - return null; - } - } - else { - return property.value; - } - }); - - } - }); - - + .controller('Umbraco.PropertyEditors.FileUploadController', fileUploadController); })(); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.controller.js index c483e83845..cfb15dc8b7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.controller.js @@ -214,55 +214,4 @@ angular.module('umbraco') $scope.$on('$destroy', function () { unsubscribe(); }); - }) - .run(function (mediaHelper, umbRequestHelper) { - if (mediaHelper && mediaHelper.registerFileResolver) { - - //NOTE: The 'entity' can be either a normal media entity or an "entity" returned from the entityResource - // they contain different data structures so if we need to query against it we need to be aware of this. - mediaHelper.registerFileResolver("Umbraco.ImageCropper", function (property, entity, thumbnail) { - if (property.value && property.value.src) { - if (thumbnail === true) { - return mediaHelper.getProcessedImageUrl(property.value.src, - { - animationprocessmode: "first", - mode: "max", - width: 500 - }) - .then(function (url) { - return url; - }); - - } - else { - return property.value.src; - } - - //this is a fallback in case the cropper has been asssigned a upload field - } - else if (angular.isString(property.value)) { - if (thumbnail) { - - if (mediaHelper.detectIfImageByExtension(property.value)) { - - var thumbnailUrl = umbRequestHelper.getApiUrl( - "imagesApiBaseUrl", - "GetBigThumbnail", - [{ originalImagePath: property.value }]); - - return thumbnailUrl; - } - else { - return null; - } - - } - else { - return property.value; - } - } - - return null; - }); - } });