How to show the selected image file without saving file in the disk before upload
I was thinking a way to show images before actually saving them on the server. I would say to preview images using javascript. Obviously asp.net file input control does not like post-backs when it has a selected file. This idea is to preview the selected image by saving the file as byte[] array in the session and assigning the file to a src (ImageUrl) of a image element(asp.net Image) in the very subsequent request. I have used jQuery to simplify the battle with asp.net rendered domain model. First hurdle, simple jQuery ajax didnt posted my selected image file. So I needed to find a way to post my selected file, then found a nice little plugin so called jQuery AjaxForm. This plugin nicely did the trick. I manage to change the form action for a bit and post the form to GenericHanlder. As soon I found the posted file, I get the converted file in to a System.Drawing.Image and saved it in the session. Finally carefully reverted the asp.net from action to it's original value.
HttpPostedFile file = context.Request.Files[0];If we request GenericHanlder again, it can retreive the image from session and serve as an image. So what I did was in the success event of jQuery AjaxForm post, assign the GenericHandler.ashx to src of the preview image. As a result, there will be a second subsequent request just after the first form post to the Generic Hander. Now I distinguish the two requests and for the second request I serve the image from the session after converting image object in to a byte[] array using a momery stream.
image = Bitmap.FromStream(file.InputStream);
context.Session["image"] = image;
MemoryStream stream = new MemoryStream();
image.Save(stream, format);
context.Response.BinaryWrite(stream.ToArray());
Memeory:
Saving the image in the session is only between two consecutive requests. First request creates the image and save it in the session. Then the second request consumes the image, remove the image from session and dispose it. So memory use of the server is instantaneous. Producer consumer fashion.
Markup:
<%@ Page Language="C#" %>
<html>
<head id="Head2" runat="server">
<script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script src="Scripts/jquery-form.js" type="text/javascript"></script>
<script language="javascript" type="text/javascript">
function ShowFile() {
var formId = '<%= this.Form.ClientID %>';
var imageId = '<%=this.imageView.ClientID %>';
var fileUploadId = '<%=fuFileUpload.UniqueID %>';
var r = Math.floor(Math.random() * 999999);
var action = $('#' + formId).attr('action');
$('#' + formId).attr('action', 'GenericHandler.ashx?f=' + fileUploadId);
$('#' + formId).ajaxForm(function () {
$('#' + imageId).attr('src', 'GenericHandler.ashx?s=' + fileUploadId + '&r=' + r);
$('#' + imageId).show();
$('#' + formId).attr('action', action);
});
$('#' + formId).submit();
}
</script>
</head>
<body>
<form id="form2" runat="server">
<asp:FileUpload runat="server" ID="fuFileUpload" onchange="javascript:ShowFile();" />
<asp:Button ID="Button1" runat="server" Text="Save" />
<hr />
<asp:Image ID="imageView" runat="server" alt="Thumbnail" Style="display: none" />
</form>
</body>
</html>
Generic Handler:
public class GenericHandler : IHttpHandler, IRequiresSessionStateReferences: Many thanks to following people for their work, without them I would not have achive this.
{
public void ProcessRequest(HttpContext context)
{
string f = context.Request.QueryString.Get("f");
string s = context.Request.QueryString.Get("s");
if (!string.IsNullOrEmpty(f))
{
HttpPostedFile file = context.Request.Files[f];
if (file == null)
HttpContext.Current.ApplicationInstance.CompleteRequest();
else
{
List<string> keys = new List<string>();
foreach (string key in context.Session.Keys) if (key.StartsWith(f)) keys.Add(key);
foreach (string key in keys) context.Session.Remove(key);
System.Drawing.Image image = Bitmap.FromStream(file.InputStream);
context.Session[f + "image"] = image;
context.Session[f + "contextType"] = context.Request.Files[0].ContentType;
context.Response.Flush();
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
}
else if (!string.IsNullOrEmpty(s))
{
string ck = s + "contextType";
string ik = s + "image";
if (context.Session[ck] == null || context.Session[ik] == null)
{
HttpContext.Current.ApplicationInstance.CompleteRequest();
if (context.Session[ck] != null) context.Session.Remove(ck);
if (context.Session[ik] != null) context.Session.Remove(ik);
}
else
{
using (System.Drawing.Image image = (System.Drawing.Image)context.Session[ik])
{
context.Response.Clear();
context.Response.ClearHeaders();
string type = context.Session[ck].ToString().ToLower();
System.Drawing.Imaging.ImageFormat format = System.Drawing.Imaging.ImageFormat.Gif;
bool isValid = true;
if (type.Contains("bmp")) format = System.Drawing.Imaging.ImageFormat.Bmp;
else if (type.Contains("jpg") || type.Contains("jpeg")) format = System.Drawing.Imaging.ImageFormat.Jpeg;
else if (type.Contains("png")) format = System.Drawing.Imaging.ImageFormat.Png;
else if (type.Contains("gif")) format = System.Drawing.Imaging.ImageFormat.Gif;
else if (type.Contains("wmf")) format = System.Drawing.Imaging.ImageFormat.Wmf;
else if (type.Contains("tiff") || type.Contains("tif")) format = System.Drawing.Imaging.ImageFormat.Tiff;
else if (type.Contains("exif")) format = System.Drawing.Imaging.ImageFormat.Exif;
else isValid = false;
if (isValid)
{
using (MemoryStream stream = new MemoryStream())
{
image.Save(stream, format);
context.Response.BinaryWrite(stream.ToArray());
context.Response.ContentType = type;
}
}
context.Session.Remove(ck);
context.Session.Remove(ik);
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
}
}
}
public bool IsReusable
{
get
{
return false;
}
}
}