We had a long term problem about image resizing and cropping. Our problem was if we resize in server side, the image quality demolished and we can’t crop according to aspect ratio as uploading image can be in any size and any dimension. For a B2B type of project , we faced it a lot as user of the website needs to upload image, they are not resizing by themselves and uploading big images for their post which was making the site slow to load.
Finally, I made a control which forcefully resized the uploaded image into my required size keeping the correct ratio of the original image and its quality. After that, user has the option to choose their cropping portion.
Here’s my canvas where user can do cropping:
After cropping, they can review the cropped image and have a chance to make a different crop again and upload the required size in a proportional way (keeping the aspect ratio that I have fixed for the image).
After uploading the image, it will show a preview of the uploaded image without page refreshing.
Resizing Algorithm
All the process is done with JavaScript, JQuery and AJAX. So, there’s no postback or page refresh needed and this resizing, cropping, uploading procedure is now more professional. I can set both portrait and landscape image ratio to crop without distorting the current ratio of the image. For that, I have developed my own resizing algorithm and implemented with JavaScript. Here’s the algorithm in JavaScript format:
function ImageResizer(canvasWidth, canvasHeight, sourceWidth,
sourceHeight, destinationX, destinationY, destinationWidth, destinationHeight) {
var canvasRatio = canvasWidth / canvasHeight;
var sourceRatio = sourceWidth / sourceHeight;
if (sourceWidth > canvasWidth || sourceHeight > canvasHeight) {
if (canvasRatio >= 1) {
if (sourceRatio <= 1) {
destinationHeight = canvasHeight;
destinationWidth = destinationHeight * sourceRatio;
destinationX = (canvasWidth - destinationWidth) / 2;
destinationY = 0;
}
else if (sourceRatio > 1) {
if (canvasRatio < sourceRatio) {
destinationWidth = canvasWidth;
destinationHeight = destinationWidth / sourceRatio;
destinationX = 0;
destinationY = (canvasHeight - destinationHeight) / 2;
} else if (canvasRatio >= sourceRatio) {
destinationHeight = canvasHeight;
destinationWidth = destinationHeight * sourceRatio;
destinationX = (canvasWidth - destinationWidth) / 2;
destinationY = 0;
}
}
}
else if (canvasRatio < 1) {
if (sourceRatio >= 1) {
destinationWidth = canvasWidth;
destinationHeight = destinationWidth / sourceRatio;
destinationX = 0;
destinationY = (canvasHeight - destinationHeight) / 2;
}
else if (sourceRatio < 1) {
if (canvasRatio > sourceRatio) {
destinationHeight = canvasHeight;
destinationWidth = destinationHeight * sourceRatio;
destinationX = (canvasWidth - destinationWidth) / 2;
destinationY = 0;
} else if (canvasRatio <= sourceRatio) {
destinationWidth = canvasWidth;
destinationHeight = destinationWidth / sourceRatio;
destinationX = 0;
destinationY = (canvasHeight - destinationHeight) / 2;
}
}
}
}
else {
destinationWidth = sourceWidth;
destinationHeight = sourceHeight;
destinationX = (canvasWidth - sourceWidth) / 2;
destinationY = (canvasHeight - sourceHeight) / 2;
}
console.log("img.width=" + sourceWidth + " img.height=" +
sourceHeight + " destinationX=" + destinationX +
" destinationY=" + destinationY + " destinationWidth=" +
destinationWidth + " destinationHeight=" + destinationHeight);
}
To understand the algorithm, you have to consider the below image:
After getting all appropriate parameters, you have to pass the values to a JavaScript method named CanvasRenderingContext2D.drawImage()
of the Canvas
2D API to draw an image onto the canvas.
Along with my resizer algorithm, I have applied a JQuery cropping API called “jquery.Jcrop.js”.
I have uploaded all my source code for this control on my Git Hub account as well for the help of other programmers. I am now showing how to use the control:
Source Code Structure
The F-ImageUploader is the folder which contains all the required files for the control:
- ImageResizeNCrop.js contains all JavaScript code for resizing, cropping and saving.
- An ASP.NET Handler file (HandlerImageUploader.ashx) is used to save the file with ajax.
- CMS_ImageResizeNCropp_CS.aspx and CMS_ImageResizeNCropp_VB.aspx are the container for control which will open in fancybox iframe.
- ASP.NET custom controller Control_CMS_ImageResizeNCropp_CS.ascx and Control_CMS_ImageResizeNCropp_VB.ascx are used to quickly plug and play the control by dragging from VS Solution Explorer.
- Images will save on /Admin/Content folder.
In this article, I am not going to explain each and every code. If you are an ASP.NET and JavaScript developer, you can easily understand the source code from the hints and pin points that I am explaining here.
How to use the controls on web page?
Here, Width
and Height
are your required image dimensions. The image will be cropped according to that ratio. ButtonName
is your required text to show on button. Also, you can pass your CSS to that control by CssClass
property.
How to Get the Uploaded Image from the Control?
First, have a look at controller markup:
<%@ Control Language="C#" AutoEventWireup="true"
CodeFile="Control_CMS_ImageResizeNCropp_CS.ascx.cs" Inherits="Control_CMS_ImageResizeNCropp_CS" %>
<div class="row">
<div class="col-xs-12">
<asp:Image ID="imgResultImage" runat="server"
style="display:none;border: rgba(128, 128, 128, 0.33) dashed 1px;" />
<asp:HiddenField ID="hdnResultImage" runat="server" />
</div>
<div class="col-xs-12" style="margin-top:5px;">
<a href='/F-ImageUploader/CMS_ImageResizeNCropp_CS.aspx?controlID=
<%= this.ID %>&width=<%= Width %>&height=<%= Height %>'
class="imageUpload btn btn-primary fancybox.iframe
<%= CssClass %>" ><%= ButtonName %></a>
</div>
</div>
Here's a hidden file named hdnResultImage. You can access the field from the control object as the hidden field is a public
property.
Source Code
https://github.com/debchy/ResizeNCrop
Reference
- Javascript
drawImage
https://developer.mozilla.org/en/docs/Web/API/CanvasRenderingContext2D/drawImage - Jquery Cropper API: http://jcrop.org
CodeProject