Crop Resize Upload Images in C# MVC3, MVC4 using Jquery, Razor

26453
Views
132
37
132

Recently I came across a requirement for an C# MVC4 application which allows user to register and upload their profile images. I have been asked by the Business to have a nice functionality that allows users to select images from their desktops and crop them or resize them to a standard size of a profile image say 150px X 150px. I was evaluating all the possible ways to process an image. I came across an article by Michael Gerety which was pretty cool but lot of users were confused where to fit in the pieces of code posted in that article. So I thought that it would be helpful for developers if I put everything in one place along with Source Code.

Let us see how easily we will do it using ASP.NET MVC4 or 3 Razor helpers, the FileUpload and WebImage helpers and jCrop, an excellent jQuery plugin for image cropping.

Requirements:

1.MVC3 or MVC4 with .net 4.0
2.Nuget Packages
3.Jcrop jquery (download from here)

Lets install Nuget packages first

To install ASP.NET Web Helpers Library, run the following command in the Package Manager Console

PM> Install-Package microsoft-web-helpers

Note: Any errors in installing please refer this question and answer

Also add reference to System.Web.Helpers.

Creating View Models:

Create a view model for displaying and the editing view

namespace TestMVC4.Models
{
     
public class ProfileViewModel
 
{
     
[UIHint("ProfileImage")]
     
public string ImageUrl { get; set; }
 
}

 
public class EditorInputModel
   
{
         
public ProfileViewModel Profile { get; set; }
         
public double Top { get; set; }
         
public double Bottom { get; set; }
         
public double Left { get; set; }
         
public double Right { get; set; }
         
public double Width { get; set; }
         
public double Height { get; set; }
     
}

}

Creating Editor View for the Image

Create a Razor view named Editor.cshtml. and dont forget to include Jcrop.js and Jcrop.css file you downloaded.
(The tags are not closed properly.. so please check the tags while using.. I need to tune my Text editor..)

 @model TestMVC4.Models.EditorInputModel
     link href
="@Url.Content("~/Content/jquery.Jcrop.css")" rel="stylesheet" type="text/css" />
     script src
="@Url.Content("~/Scripts/jquery.Jcrop.js")" type="text/javascript">

  div id
="mainform">
 
@using(Html.BeginForm("Edit","Profile", FormMethod.Post))
 
{
     
@Html.DisplayFor(x=>x.Profile.ImageUrl)        
     
@Html.HiddenFor(x=>x.Left)
     
@Html.HiddenFor(x=>x.Right)
     
@Html.HiddenFor(x=>x.Top)
     
@Html.HiddenFor(x=>x.Bottom)
     
@Html.HiddenFor(x => x.Profile.ImageUrl)
     input type
='submit' name='action' value='Crop' />
 
}

 script type
="text/javascript">
   $
(function () {
         jQuery
('#profileImageEditor').Jcrop({
            onChange
: showPreview,
            onSelect
: showPreview,
           setSelect
: [@Model.Top, @Model.Left, @Model.Right, @Model.Bottom],
          aspectRatio
: 1
       
});
     
});


   
function showPreview(coords)
     
{
         
if (parseInt(coords.w) > 0)
         
{
             $
('#Top').val(coords.y);
              $
('#Left').val(coords.x);
             $
('#Bottom').val(coords.y2);
              $
('#Right').val(coords.x2);

             
var width = @Model.Width;
             
var height = @Model.Height;
           
var rx = 100 / coords.w;
             
var ry = 100 / coords.h;

             jQuery
('#preview').css({
                 width
: Math.round(rx * width) + 'px',
                height
: Math.round(ry * height) + 'px',
                 marginLeft
: '-' + Math.round(rx * coords.x) + 'px',
                  marginTop
: '-' + Math.round(ry * coords.y) + 'px'
             
});
         
}
   
}
/script>

Create Editor Template:

Create a folder named DisplayTemplates under Shared folder and add a partial view named profileImage.cshtml and add the following code into it.

 @model System.String
   div id
="cropContainer">
     div id
="cropPreview">
        img src
="@(String.IsNullOrEmpty(Model) ? "" : Model)" id="preview" />
   
/div>
     div id
="cropDisplay">
         img src
="@(String.IsNullOrEmpty(Model) ? "" : Model)" id="profileImageEditor" />
   
/div>
 
/div>

So now we have a preview container and a actual image container.

Now lets add File upload functionality

Add a view named Index.cshtml. This is our actual image upload view and add the code into it

 @model TestMVC4.Models.ProfileViewModel
 
@using Microsoft.Web.Helpers;

   
@using (Html.BeginForm("Upload", "Profile", FormMethod.Post, new { @encType = "multipart/form-data" }))
   
{
       
if (Model.ImageUrl != "")
       
{
    img src
="@Model.ImageUrl"  style="width:100px;height:100px"/>
       
}
         
@FileUpload.GetHtml(initialNumberOfFiles:1, allowMoreFilesToBeAdded: true, includeFormTag: false, addText: "Add Files", uploadText: "Upload File")


     input type
="submit" name="submit" value="upload" />
     
}

We are posting this form to an action Upload in the controller named ProfileController
Dont forget to include the Web.Helpers namespace in the page
The

allowMoreFilesToBeAdded: true attribute helps to upload multiple images. ( we are not implementing this functionality here now)

Creating the controller and the Action methods

Create a controller named ProfileController or what ever name you prefer and add the below code.

 public class ProfileController : Controller
   
{
       
//
       
// GET: /Profile/

       
public ActionResult Index()
       
{
           
ProfileViewModel pmodel = new ProfileViewModel();

           
return View(pmodel);
       
}

 
public ActionResult Upload(ProfileViewModel model)
   
{
     
var image = WebImage.GetImageFromRequest();

     
if (image != null)
       
{
           
if (image.Width > 500)
         
{
             image
.Resize(500, ((500 * image.Height) / image.Width));
         
}

         
var filename = Path.GetFileName(image.FileName);
         image
.Save(Path.Combine("~/Images", filename));
         filename
= Path.Combine("~/Images", filename);  
         model
.ImageUrl = Url.Content(filename);
           
var editModel = new EditorInputModel()
               
{
                   
Profile = model,
                   
Width = image.Width,
                   
Height = image.Height,
                   
Top = image.Height * 0.1,
                   
Left = image.Width * 0.9,
                   
Right = image.Width * 0.9,
                   
Bottom = image.Height * 0.9
               
};
     
return View("Editor", editModel);

   
}

     
return View("Index", model);
 
}

 
public ActionResult Edit(EditorInputModel editor)
         
{
           
var image = new WebImage("~" + editor.Profile.ImageUrl);
           
var height = image.Height;
           
var width = image.Width;
           image
.Crop((int)editor.Top, (int)editor.Left, (int)(height - editor.Bottom), (int)(width - editor.Right));
           
var originalFile = editor.Profile.ImageUrl;
           editor
.Profile.ImageUrl = Url.Content("~/ProfileImages/" + Path.GetFileName(image.FileName));
           image
.Resize(100, 100, true, false);
           image
.Save(@"~" + editor.Profile.ImageUrl);
           
System.IO.File.Delete(Server.MapPath(originalFile));
           
return View("Index", editor.Profile);
       
}

   
}
}

Create a Folder to Save the Images

Create a folder named Images to save the images temporarily and delete after its processed successfully.
Create a folder named ProfileImages to save the cropped images.

CSS for the Editor view

To align the preview and display container in the editor view add this CSS to Jcrop.css file

#cropPreview
{
float : left;
overflow
: hidden;
width
: 100px;
height
: 100px;
}

#cropDisplay
{
float : left;
clear
: right ;
}

Thats it.. Compile the code and run..

You will see the upload button to upload your images and on submitting it will take to a editor view for cropping.

Thanks for reading!! I will post the source code soon!!

Post Comment | flag
Gokul A
Submitted on: Feb 11, 12 at 2:20AM

0 Comments

Wow!! awesome post.. I was looking for this!! thanks!!

by : Mike Carpenter on : Feb 21, 12 at 1:47AM

It would be nice if you post the project for download. :-)

by : Mike Carpenter on : Feb 21, 12 at 2:04AM

image.Save(@"~" + editor.Profile.ImageUrl);
received a error parameter not valid

by : Cap paf on : Apr 30, 12 at 4:04AM

This does not work with MVC4, see http://nuget.org/packages/microsoft-web-helpers/2.0.20505.2

installing web helpers in mvc4 will uninstall the correct version of razor

Additionally some of the steps are in the wrong order, the controller should be created before all the views

by : Luke Walsh on : Dec 02, 12 at 11:34PM

So is there no way to make it work on mvc4?
if not, does someone know how to upload images in MVC4???

by : syl sham on : Jan 11, 13 at 5:43PM

Hello strangely in IE the cropping does not work as expected

by : Vineet Puranik on : Apr 29, 13 at 1:04PM

Where do we have to call de profileImage.cshtml template? There is not any reference to it in the code.

Luk: "If your application is ASP.NET MVC 4 you should install Microsoft.AspNet.Web.Helpers.Mvc instead."

so it works on MVC 4.

Cap: by removing the "@" should work.

by : moar alejos on : Jul 11, 13 at 1:35PM

Be able to provide the source code it, tks

by : joey li on : Aug 14, 13 at 1:48PM

plz provide this project for download

by : mahesh p on : Sep 06, 13 at 4:24PM

The temp img tag prior to uploading doesn't work among other things (In the index view). The partial view is never called. The width is not correct. Haven't looked at it thoroughly so I haven't found the problems quite yet.

by : Amanda VanderWall on : Sep 19, 13 at 2:35AM

Oh I see. The partial view gives the temp image from the Upload Action to the Editor view. How does it find this view? Thanks.

by : Amanda VanderWall on : Sep 19, 13 at 3:21AM

Does the Data Annotation [UIHint("ProfileImage")] bind the ImageUrl to the partial view ProfileImage.cshtml using System.String?

by : Amanda VanderWall on : Sep 19, 13 at 3:26AM

gj

by : Jn Roberts on : Oct 02, 13 at 9:42PM

How do you get the Partial view Crop feature to appear as a pop up?

by : Jn Roberts on : Oct 02, 13 at 9:42PM

Hi,

Where is the WebImage.GetImageFromRequest method?

by : altug d on : Oct 03, 13 at 8:03PM

Oh sorry, problem solved :)
Thanks...

by : altug d on : Oct 03, 13 at 8:13PM

Thanks..

by : Bac Gs on : Oct 06, 13 at 8:15PM

where is the source code? plz share it!

by : mürsel 111 on : May 07, 15 at 5:49PM

Post your Comment