Changing Media Image Type and using ImageProcessor with external images
Hey all,
Two questions for everyone:
I'm trying to pass an image processor crop to an external image as per the usage examples on the ImageProcessor Site but it doesn't seem to be working?
I'm able to use the ".GetCropUrl" perfectly on internal images thanks to the manual change to the Media Type I've put in place based on the examples here and here [Thanks Jan!]
In the kit I'm developing I now need to ensure this Media Type change is actually set on install of the kit and wondered if anyone could point me in the right direction to be able to do this via events and which one?
Jeavon,
Thanks for responding, time is running out for development and I'm hoping to sort this out tonight!
In response, I've changed the standard media image type umbracoFile property to use the image cropper instead of upload data type so the kit can benefit from the power as shown in the links in my op. 😎
As I had to do this manually I wasn't sure if the change would be packaged up In the kit for distribution and want to ensure that this is able to be done or think of something else.😖
As I can't see anywhere to choose the modified media type in the package creation process so wondered if it could be done in code? 🤔
Ok, so you want to create a package which when installed checks the default "Image" media type to see if the umbracoFile property is a Cropper or a Upload type and if it's a Upload type convert it to a Cropper (likely creating a Cropper data type first)?
The good news it that it can be done using a Package Action, however I can't find much documentation at the moment. Here is a example which used to execute XDT files on config file. It is then referenced in the package.xml shipped with the package here.
Once you have a package action executing you will need to use the ContentTypeType (for MediaTypes) & DataType Services to do the checking/modification described.
First, I've been in to check the links now, and thankfully I'm already using a package actions for the kit which checks to make sure the default content is added and/or reloads the content tree:
public bool Execute(string packageName, XmlNode xmlData)
{
var contentService = ApplicationContext.Current.Services.ContentService;
try
{
var homeNode = contentService.GetRootContent().FirstOrDefault();
if (homeNode == null || !contentService.HasPublishedVersion(homeNode.Id))
{
contentService.PublishWithChildrenWithStatus(homeNode);
LogHelper.Info<NgUskInstaller>("INSTALLER: Home Node and children were just added to the site");
}
else
{
contentService.RePublishAll();
contentService.RebuildXmlStructures();
LogHelper.Info<NgUskInstaller>("INSTALLER: Home Node and children were just refreshed and the xml tree was rebuilt");
}
return true;
}
catch (Exception exception)
{
LogHelper.Error<NgUskInstaller>("INSTALLER: Error at execute NgUskInstaller package action", exception);
return false;
}
}
I now need to work out where to add this into there; I've not used the data service so this should be fun!
Second, did you have any thoughts on the Image cropper issue I mentioned with external images?
I've watched your uHangout ep30 and probably missed it but I've followed the examples on the ImageProcessor website but the "external" thumbnail is still the "bigger" image squashed into the space?
I see you and Jeavon have been busy so I'll attempt to answer the non-ish-umbraco part.
As far as I'm aware .GetCropUrl() only works with IPublishedContent referencing a media item.
By external images do you mean images outwith the domain? i.e ones that should be prefixed with remote.axd? The method will not work out of the box with those at all.
If you mean images stored on a cloud service like Azure you will need to use an IFileSystem implementation that stores the relative path for the method to work.
The .GetCropUrl does work fine with the local IPublishedContent, by remote I mean hosted on another site as my client has many satellite branches and they share media.
So in the example code above we're using the RJP MultiUrlPicker to be able to link to the satellite site content, however passing in the http://www.external.url/path/to/remote/image?crop=top,left,width,height query string as per the "pixel" example on the imageprocessor.org site isn't cropping the image at all; neither is the www.external.url/path/to/remote/image?crop=left,top,right,bottom&cropmode=percentage percentage example?
Unless your remote server also happens to have ImageProcessor installed I think you are after the Remote Files feature.
e.g. /remote.axd/www.external.url/path/to/remote/image?crop=left,top,right,bottom&cropmode=percentage
Umbraco GetCropUrl uses percentage mode cropping so you would need to add cropmode=percentage as I have done in the example above if you want it to crop the external image in a similar way. See the crop documentation for more info
I'm guessing then somehow I'll need to be able to add a url "whitelist" to the services.service.whitelist section in the security config to be able to link to said remote images? I'll discuss this with the client then.
With the Media Type change I've ended up with the following method in my StarterKitInstaller.cs code:
public static bool ChangeImageMediaType()
{
var success = false;
try
{
var contentTypeService = ApplicationContext.Current.Services.ContentTypeService;
var dataTypeService = ApplicationContext.Current.Services.DataTypeService;
var mediaService = ApplicationContext.Current.Services.MediaService;
//Given a `DataTypeService` object get the DataType by propertyEditorAlias
var generalCropper = dataTypeService.GetDataTypeDefinitionByPropertyEditorAlias("Umbraco.ImageCropper");
//Given a 'ContentTypeService' object get the MediaType that we're changing,
var mediaImageType = contentTypeService.GetMediaType("Image");
//Given a `MediaService` object get MediaType by its Id,
var mediaImage = mediaService.GetById(mediaImageType.Id);
//Set the value of the propertyTypeAlias to the new dataType
mediaImage.SetValue("umbracoFile", generalCropper);
//and saves the Media through the `MediaService`
mediaService.Save(mediaImage);
LogHelper.Info<NgUskInstaller>("INSTALLER: Updating Image Media Type to use Image Cropper succeeded!");
success = true;
}
catch (Exception exception)
{
success = false;
LogHelper.Error<NgUskInstaller>("INSTALLER: USK installation failed. An issue occured updating Image Media Type to use Image Cropper.", exception);
}
return success;
}
But I need to set up a new instance to test this and will report back! :-D
Looks good. Yes whitelist configuration is documented here. Most people won't have security.config with their Umbraco installs though so you may need to think about that.
Just wanted to say thanks for the responses from both of you!
With everything else (including BT) I simply missed responding until now, you both were absolutely correct in the remote.axd call being the key!
Once I installed the full ImageProcessor package, and manually added the test "lorempixel.com" url to the whitelist the thumbnails loaded perfectly!
#h5yr! x2
[Now to add a dashboard to the developers area to enable backoffice updates to the config file ... but that can wait]
Sadly I can't say the same for my ImageMediaTypeSwap code.
I'm receiving the following error and have chopped and changed my code to try everything I can see but still to no avail on the ImageCropper PropertyEditorType update.
INSTALLER: ChangeImageMediaType failed. An issue occurred updating Image Media Type to use Image Cropper.
System.NullReferenceException: Object reference not set to an instance of an object.
at NG.USK.PackageActions.ImageMediaTypeChange.ChangeImageMediaType() in E:\Users\jon\Documents\Visual Studio 2015\Projects\NGS\src\NG.USK\PackageActions\ImageMediaTypeChange.cs:line 46
Line 46 is: mediaImage.SetValue("umbracoFile", generalCropper);
I'm posting my code below and going to bed, maybe someone can see what I'm not:
using System;
using System.Linq;
using System.Xml;
using umbraco.interfaces;
using Umbraco.Core;
using Umbraco.Core.Logging;
using umbraco.BusinessLogic;
using umbraco.cms.businesslogic.packager.standardPackageActions;
using Umbraco.Core.Models;
namespace NG.USK.PackageActions
{
public class ImageMediaTypeChange : IPackageAction
{
public static bool ChangeImageMediaType()
{
var success = false;
try
{
//Create the `DataTypeService` object for later use
var dataTypeService = ApplicationContext.Current.Services.DataTypeService;
//Create the other services we need
var mediaService = ApplicationContext.Current.Services.MediaService;
var contentTypeService = ApplicationContext.Current.Services.ContentTypeService;
//Given a `DataTypeService` object get the DataType by propertyEditorAlias
var generalCropper = dataTypeService.GetDataTypeDefinitionByPropertyEditorAlias("Umbraco.ImageCropper");
//Check if the DataType is null
if (generalCropper == null) return false;
//Given a 'ContentTypeService' object get the MediaType that we're changing,
var mediaImageType = contentTypeService.GetMediaType("Image");
//PropertyType propertyType = mediaImageType.PropertyTypes.First(x => x.Alias == "umbracoFile");
mediaImageType.RemovePropertyType("umbracoFile");
contentTypeService.Save(mediaImageType);
var mediaImage = mediaService.GetById(mediaImageType.Id);
var noCropper = false;
foreach (var property in mediaImage.PropertyTypes.Where(property => property.PropertyEditorAlias != "Umbraco.ImageCropper"))
{
noCropper = true;
}
if (noCropper == true)
{
mediaImage.SetValue("umbracoFile", generalCropper);
}
//and saves the Media through the `MediaService`
mediaService.Save(mediaImage);
LogHelper.Info<NgUskInstaller>("INSTALLER: Updating Image Media Type to use Image Cropper in ChangeImageMediaType.cs succeeded!");
success = true;
}
catch (Exception exception)
{
success = false;
LogHelper.Error<NgUskInstaller>("INSTALLER: ChangeImageMediaType failed. An issue occurred updating Image Media Type to use Image Cropper.", exception);
}
return success;
}
public string Alias()
{
return "ImageMediaTypeChange";
}
public bool Execute(string packageName, XmlNode xmlData)
{
try
{
return ChangeImageMediaType();
}
catch (Exception doh)
{
LogHelper.Error<NgUskInstaller>("INSTALLER: Error at execute ChangeImageMediaType package action", doh);
return false;
}
}
public bool Undo(string packageName, XmlNode xmlData)
{
return true;
}
public XmlNode SampleXml()
{
const string sample = "<Action runat=\"install\" undo=\"true\" alias=\"ImageMediaTypeChange\" />";
return ParseStringToXmlNode(sample);
}
private static XmlNode ParseStringToXmlNode(string value)
{
var xmlDocument = new XmlDocument();
var xmlNode = AddTextNode(xmlDocument, "error", "");
try
{
xmlDocument.LoadXml(value);
return xmlDocument.SelectSingleNode(".");
}
catch
{
return xmlNode;
}
}
private static XmlNode AddTextNode(XmlDocument xmlDocument, string name, string value)
{
var node = xmlDocument.CreateNode(XmlNodeType.Element, name, "");
node.AppendChild(xmlDocument.CreateTextNode(value));
return node;
}
}
}
Changing Media Image Type and using ImageProcessor with external images
Hey all,
Two questions for everyone:
Hi Jon,
What do you mean by "media type", format, jpg, png etc...?
Jeavon
Jeavon, Thanks for responding, time is running out for development and I'm hoping to sort this out tonight!
In response, I've changed the standard media image type umbracoFile property to use the image cropper instead of upload data type so the kit can benefit from the power as shown in the links in my op. 😎 As I had to do this manually I wasn't sure if the change would be packaged up In the kit for distribution and want to ensure that this is able to be done or think of something else.😖 As I can't see anywhere to choose the modified media type in the package creation process so wondered if it could be done in code? 🤔
Does that help clarify things? Cheers, J
Ok, so you want to create a package which when installed checks the default "Image" media type to see if the umbracoFile property is a Cropper or a Upload type and if it's a Upload type convert it to a Cropper (likely creating a Cropper data type first)?
That's the ticket!! As I said I've done all the code in my instance but need it to be part of the package install?
I just need to see an example or link for a package install event and how to check media type properties then eh?
The good news it that it can be done using a Package Action, however I can't find much documentation at the moment. Here is a example which used to execute XDT files on config file. It is then referenced in the package.xml shipped with the package here.
Once you have a package action executing you will need to use the ContentTypeType (for MediaTypes) & DataType Services to do the checking/modification described.
Thank you Jeavon! Sorry for the delay, had to read to the kids! I'm on my way back to my office now and will read up and sort this out!
h5yr!
No problem, what does your package contain aside from switching Upload to Cropper?
Thanks Jeavon,
First, I've been in to check the links now, and thankfully I'm already using a package actions for the kit which checks to make sure the default content is added and/or reloads the content tree:
I now need to work out where to add this into there; I've not used the data service so this should be fun!
Second, did you have any thoughts on the Image cropper issue I mentioned with external images?
I've watched your uHangout ep30 and probably missed it but I've followed the examples on the ImageProcessor website but the "external" thumbnail is still the "bigger" image squashed into the space?
J
Hey Jon,
I see you and Jeavon have been busy so I'll attempt to answer the non-ish-umbraco part.
As far as I'm aware
.GetCropUrl()
only works withIPublishedContent
referencing a media item.By external images do you mean images outwith the domain? i.e ones that should be prefixed with
remote.axd
? The method will not work out of the box with those at all.If you mean images stored on a cloud service like Azure you will need to use an
IFileSystem
implementation that stores the relative path for the method to work.Hope that helps.
James
James,
The
.GetCropUrl
does work fine with the localIPublishedContent
, by remote I mean hosted on another site as my client has many satellite branches and they share media.So in the example code above we're using the RJP MultiUrlPicker to be able to link to the satellite site content, however passing in the
http://www.external.url/path/to/remote/image?crop=top,left,width,height
query string as per the "pixel" example on the imageprocessor.org site isn't cropping the image at all; neither is thewww.external.url/path/to/remote/image?crop=left,top,right,bottom&cropmode=percentage
percentage example?Also, out of curiosity, with either of the linked examples quoted above, can the position points be percentages? For example:
http://www.external.url/path/to/remote/image?crop=40%,25%,width,height
Thanks for the help! :-D
Unless your remote server also happens to have ImageProcessor installed I think you are after the Remote Files feature.
e.g.
/remote.axd/www.external.url/path/to/remote/image?crop=left,top,right,bottom&cropmode=percentage
Umbraco GetCropUrl uses percentage mode cropping so you would need to add cropmode=percentage as I have done in the example above if you want it to crop the external image in a similar way. See the crop documentation for more info
Thanks Jeavon,
I'm guessing then somehow I'll need to be able to add a url "whitelist" to the services.service.whitelist section in the security config to be able to link to said remote images? I'll discuss this with the client then.
With the Media Type change I've ended up with the following method in my StarterKitInstaller.cs code:
But I need to set up a new instance to test this and will report back! :-D
Looks good. Yes whitelist configuration is documented here. Most people won't have security.config with their Umbraco installs though so you may need to think about that.
Jeavon,
Right then! I'll make sure to add this to the growing list of third-party plugins to add to the install! :-D
#standingontheshouldersofgiants!
With the remote images I've added the following for now:
var thumbnail = (thumb.Id == null) ? string.Format("/remote.axd/{0}{1}", thumb.Url.Substring(thumb.Url.IndexOf("://", StringComparison.Ordinal)+3), "?crop=0,0,400,250") : Umbraco.TypedMedia((int)thumb.Id).GetCropUrl(400, 250);
While I think the comparison ordinal is a little OTT, I've added it to be on the safe side!
J
James & Jeavon,
Just wanted to say thanks for the responses from both of you!
With everything else (including BT) I simply missed responding until now, you both were absolutely correct in the
remote.axd
call being the key!Once I installed the full ImageProcessor package, and manually added the test "lorempixel.com" url to the whitelist the thumbnails loaded perfectly!
#h5yr! x2
[Now to add a dashboard to the developers area to enable backoffice updates to the config file ... but that can wait]
Sadly I can't say the same for my ImageMediaTypeSwap code.
I'm receiving the following error and have chopped and changed my code to try everything I can see but still to no avail on the ImageCropper PropertyEditorType update.
Line 46 is:
mediaImage.SetValue("umbracoFile", generalCropper);
I'm posting my code below and going to bed, maybe someone can see what I'm not:
Until the daylight...
J
is working on a reply...