Uploading photos with MVC
There are many articles online talking about MVC, but not many showing how to upload files. In a project I'm working on I need to have my users upload photographs and wanted them to be able to preview the photo before submitting it. Here's a screen shot of what I'm talking about.
The application allows the user to select a photo, which is then previewed. The user can then add a caption and description of the photo. During this first round the Save button is bound to the following jQuery script:
1: function uploadMemberPhoto(elem) {
2: var $elem = $(elem);
3: $("div.memberPhotoUploader").fadeIn(500);
4: var $form = $elem.parents("form");
5: $form.attr("action", "/MemberPhotos/Uploaded");
6: $elem.fadeOut(500, function () { $form[0].submit(); });
7: }
which sets the action of the form to "/MemberPhotos/Uploaded", then submits the form. The Controller action "Uploaded" handles the processing of the image.
1: public ActionResult Uploaded(HttpPostedFileBase file, FormCollection formCollection)
2: {
3: var memberPhoto = _photoHelpers.UploadMemberPhoto(file, formCollection);
4: return View("UploadedPhoto");
5: }
_photoHelpers is a helper class which does the processing of the image
1: public MemberPhoto UploadMemberPhoto(HttpPostedFileBase file, FormCollection collection)
2: {
3: var memberPhoto = new MemberPhoto();
4: try
5: {
6: if(file.ContentLength > 0)
7: {
8: var member = _repo.Get(int.Parse(collection["memberId"]));
9: var photoCaption = collection["memberPhotoCaption"];
10: var photoDescription = collection["memberPhotoDescription"];
11: var serverPath = HttpContext.Current.Server.MapPath(
12: ConfigurationManager.AppSettings["memberAvatarPath"]);
13: var memberFolder = GetMemberImageFolder(member);
14: var imagePath = serverPath memberFolder;
15:
16: if (!Directory.Exists(imagePath))
17: Directory.CreateDirectory(imagePath);
18:
19: bool success = ImageHelpers.ProcessMemberPhotoUpload(file, imagePath);
20: if(success) // insert the record
21: {
22: memberPhoto.MemberId = member.Id;
23: memberPhoto.PhotoUrl = file.FileName;
24: memberPhoto.PhotoCaption = photoCaption;
25: memberPhoto.PhotoDescription = photoDescription;
26: memberPhoto.IsApproved = false;
27: memberPhoto.IsVisible = true;
28: memberPhoto.CreateBy = member.Email;
29: memberPhoto.CreateDate = DateTime.Now;
30: memberPhoto.ModifyBy = member.Email;
31: memberPhoto.ModifyDate = DateTime.Now;
32: memberPhoto.Mode = ImageHelpers.ImageMode(file);
33: _repo.Create(memberPhoto);
34: }
35: }
36: }
37: catch (Exception ex)
38: {
39: memberPhoto = null;
40: }
41: return memberPhoto;
42: }
1: public bool ProcessMemberPhotoUpload(HttpPostedFileBase img, string fPath)
2: {
3: fPath = fPath.Replace("\\\", "\\");
4: var resizedImage = ResizeImage(img, new Size(640, 480));
5: var status = SaveImage(resizedImage, fPath, img.FileName);
6:
7: var thumbNail = ResizeImage(img, new Size(102, 77));
8: status = SaveImage(thumbNail, fPath, "thmb_" img.FileName);
9:
10: var largeThumb = ResizeImage(img, new Size(400, 600));
11: status = SaveImage(largeThumb, fPath, "lgthmb_" img.FileName);
12: return status;
13: }
The rest of the methods used in the helper class are here
1: private static Image ResizeImage(HttpPostedFileBase img, Size size)
2: {
3: var oImage = Image.FromStream(img.InputStream);
4: var sWidth = oImage.Width;
5: var sHeight = oImage.Height;
6:
7: if(size.Width >= oImage.Width && size.Height >= oImage.Height)
8: return (Image) oImage;
9:
10: float nPercent = 0;
11: float nPercentW = 0;
12: float nPercentH = 0;
13:
14: nPercentW = ((float) size.Width/(float) sWidth);
15: nPercentH = ((float) size.Height/(float) sHeight);
16:
17: if (nPercentH < nPercentW)
18: nPercent = nPercentH;
19: else
20: nPercent = nPercentW;
21:
22: int dWidth = (int) (sWidth*nPercent);
23: int dHeight = (int) (sHeight*nPercent);
24:
25: Bitmap b = new Bitmap(dWidth, dHeight);
26: Graphics g = Graphics.FromImage((Image) b);
27: g.InterpolationMode = InterpolationMode.HighQualityBicubic;
28: g.DrawImage(oImage, 0, 0, dWidth, dHeight);
29: g.Dispose();
30: return (Image) b;
31: }
32:
33: private static bool SaveImage(Image img, string savePath, string fileName)
34: {
35: var status = true;
36: try
37: {
38: var newPath = new StringBuilder(savePath).Append(fileName);
39: File.Delete(newPath.ToString());
40: img.Save(newPath.ToString(), img.RawFormat);
41: }
42: catch (Exception)
43: {
44: status = false;
45: }
46: return status;
47: }
48:
49: public string ImageMode(HttpPostedFileBase img)
50: {
51: var oImage = Image.FromStream(img.InputStream);
52: var mode = "landscape";
53: if (oImage.Width < oImage.Height) mode = "portrait";
54: oImage.Dispose();
55: return mode;
56: }
In this particular application, all photos uploaded need to be approved, so after the photo is uploaded, the page refreshes, keeping the original form action of "/MemberPhotos/UpdatePhoto"
1: public ActionResult UpdatePhoto(MemberPhoto photo)
2: {
3: photo.ModifyBy = User.Identity.Name;
4: photo.ModifyDate = DateTime.Now;
5: _repo.Edit(photo);
6: }
You may be wondering how the image is previewed. I found this article at, http: //weblogs.asp.net/imranbaloch/archive/2010/04/03/image-preview-in-asp-net-mvc.aspx and modified it a bit for my needs. This bit of javascript works like a champ.
1: function ChangeImage(fileId, imageId) {
2: $("div.memberPhotoUploader").fadeIn(500);
3: $("#form1").ajaxSubmit({ success: function (responseText) {
4: if (isImage(responseText)) {
5: var d = new Date();
6: $(imageId)[0].src = "/ImagePreview/ImageLoad?a=" d.getTime();
7: $(imageId).show();
8: $("input#uploadButton").removeClass("btnSaveDisabled")
9: .addClass("btnSaveEnabled").removeAttr("disabled").click(function () {
10: uploadMemberPhoto(this);
11: }); ;
12: } else {
13: $(imageId).hide();
14: $("div.imageTypeNotice").show();
15: }
16: $("div.memberPhotoUploader").fadeOut(500);
17: }
18: });
19: }
Happy programming from ComponentOne
James