You shouldn’t need another package to do this and should be able to achieve it using a combination of INotificationAsyncHandler<MediaSavingNotification>
and ImageSharp
which ships with Umbraco.
You could cancel the save operation when people exceed a given threshold for file size or dimensions. or you can resize it for them. This is what I am doing at the moment in v13.
/// <summary>
/// Checks the upload size and permissions to upload the filetype.
/// </summary>
/// <param name="mediaItem">The <see cref="IMedia"/> item being saved.</param>
/// <param name="notification">The <see cref="MediaSavingNotification"/>.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A task representing the asynchronous operation.</returns>
private async Task CheckUploadSizeAndPermissions(IMedia? mediaItem, MediaSavingNotification notification,
CancellationToken cancellationToken)
{
if (mediaItem == null) return;
IUser? currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity?.CurrentUser;
if(currentUser == null)
{
notification.CancelOperation(new EventMessage("Media Upload Permissions",
"Unable to detect a valid current user .", EventMessageType.Error));
return;
}
IFileSystem mediaFileSystem = _mediaFileManager.FileSystem;
int currentWidth = mediaItem.GetValue<int>(Conventions.Media.Width);
string fileType = mediaItem.GetValue<string>(Conventions.Media.Extension);
//Determine if this is a PNG file
var isPng = fileType.Equals("png", StringComparison.OrdinalIgnoreCase);
IEnumerable<string> supportedTypes = _contentSettings.Imaging.ImageFileTypes.ToList();
string imgFileProp = mediaItem.GetValue<string>(Conventions.Media.File);
// Get the relative file path
var filePath = JsonConvert.DeserializeObject<ImageCropperValue>(imgFileProp).Src;
// Get the full file system path
string originalFilePath = mediaFileSystem.GetFullPath(filePath);
// Make sure it's an image.
string extension = Path.GetExtension(originalFilePath).Substring(1);
if (extension.Equals("gif", StringComparison.InvariantCultureIgnoreCase) &&
currentUser.Groups.All(g => g.Alias != Constants.UserGroups.Example))
{
notification.CancelOperation(new EventMessage("Media Upload Permissions",
"You do not have permission to upload a file of this type.", EventMessageType.Error));
}
// If it is a supported file type and has a width greater than 4000px we need to resize it
if (supportedTypes.InvariantContains(extension) && currentWidth > 4000)
{
var resizedImage = await CreateResizedImage(mediaItem, originalFilePath, originalFilePath, 4000, 0, cancellationToken);
if (resizedImage == null)
{
notification.Messages.Add(new EventMessage("Image Resize", "Unable to resize image",
EventMessageType.Warning));
_logger.LogWarning($"There was a problem resizing image {mediaItem.Name} ({mediaItem.Id})");
}
else
{
notification.Messages.Add(new EventMessage("Image Resized",
"Your image was resized to the maximum width of 4000 pixels wide.",
EventMessageType.Info));
}
}
}
And here is the method that performs the resizing:
/// <summary>
/// Creates a resized version of the image at the size specified in the parameters.
/// </summary>
/// <param name="mediaItem">The media item to resize.</param>
/// <param name="originalFilePath">The full path of the original file.</param>
/// <param name="newFilePath">The full path of the new file.</param>
/// <param name="width">The new image width.</param>
/// <param name="height">The new image height.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A resized image object of type Image or null if there was an error resizing the image.</returns>
private async Task<Image?> CreateResizedImage(IMedia mediaItem, string originalFilePath, string newFilePath,
int width, int height, CancellationToken cancellationToken)
{
using Image img = await Image.LoadAsync(originalFilePath, cancellationToken);
var newImage = img;
try
{
if (img.Width > width || img.Height > height)
{
img.Mutate(x => x.Resize(new ResizeOptions
{
Mode = ResizeMode.Max,
Size = new Size(width, height),
Position = AnchorPositionMode.Center
}));
// Determine encoder based on file extension
IImageEncoder encoder = GetEncoderForFilePath(newFilePath);
await using var outputStream = File.Create(newFilePath);
await img.SaveAsync(outputStream, encoder, cancellationToken);
newImage = img;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "An error occurred while resizing the image.");
return null;
}
mediaItem.SetValue(Conventions.Media.Width, newImage.Width);
mediaItem.SetValue(Conventions.Media.Height, newImage.Height);
try
{
mediaItem.SetValue(Conventions.Media.Bytes, _mediaFileManager.FileSystem.GetSize(originalFilePath));
}
catch (Exception ex)
{
_logger.LogError(ex, "Error getting new resized image file size");
}
return newImage;
}
Hopefully that helps.