Ryan Ternier

Killer ASP.NET ninja coding monkeys do exist!

September 2010 - Posts

JQuery image Upload & refresh using an ASHX File part 2.

A bit ago I wrote a blog post about how to hook up a JQuery upload script go a page to asynchronously upload files to an ASHX page on a server.

For the 2nd part I’ll show you an easy snippet of code that can be used to upload and/or view the image. The example below deals with signatures, though it can be easily and quickly modified for any type of image.

I’m storing the uploaded image in a Session variable. I do this because a user might have uploaded a wrong image or they might not want to save what they uploaded. As well, once you upload an image to the server, you are going to want to let the user see it. If the image was incorrect, you’ll be writing it to the database and then retrieving it back right away, not really efficient.

Remember to include the IRequiresSessionState interface when you are creating your ASHX class so you have access to the Session.

Let’s look at some code. I have to determine what I’m doing – uploading an image, or viewing one.

Upload

string fileName = System.IO.Path.GetFileName(context.Request.Files[0].FileName);
string extention = System.IO.Path.GetExtension(context.Request.Files[0].FileName).ToLower();
HttpPostedFile file = context.Request.Files[0];
if (file.ContentLength == 0)
{
    //no file posted.
    rMessage = "There was no data found in the file. Please ensure the file being uploaded is a valid image file.";
    break;
}
byte[] bImage = new Byte[file.ContentLength];
file.InputStream.Read(bImage, 0, file.ContentLength);
context.Session["Signature"] = bImage;
if (info.Successful)
{
    rMessage = "Signature upload successful.";
}
else
{
    rMessage = "There was an error uploading your signature.";
}

All files that are uploaded are located in context.Request.Files. Seeing I’m only uploading one image, I know it’s going to be at the 0 index in the FileCollection.

Once I have my file, I want to create a byte array (byte[]) of that file, and store that in memory.

And we’re done.

View

string contentType = Microsoft.Win32.Registry.GetValue("HKEY_CLASSES_ROOT\\.PNG", "Content Type", "application/octetstream").ToString();
utility = new Utility();
double scale = utility.GetScale(signature, 450, 50);
signature = utility.ScaleByPercent(signature, (float)scale);
                
context.Response.AddHeader("Content-Disposition", "attachment; filename=UserSignature.png");
context.Response.AddHeader("Content-Length", signature.Length.ToString());
context.Response.AddHeader("Cache-Control", "no-cache, must-revalidate");
context.Response.Expires = -1;
context.Response.ContentType = contentType;                
context.Response.BufferOutput = false;                
context.Response.OutputStream.Write(signature, 0, signature.Length);

After I upload an image I change the SRC of my <img /> control so it will download the new image. I do this by adding a randomized alpha-numeric string to the end so the browser will not cache the image.

In this example I’m telling the browser it’s getting a PNG image. I am also scaling the image to be 450 by 50 (Code below).

Once I have a scaled image, I send it back down to the client.

Scaling an Image

An image might be uploaded that’s 3000x4000 or some other ugly size. No one wants to get sent an image that size on the web for previewing… no one…. So I decide to trim it down.

public double GetScale(byte[] image, double width, double height)
{
    try
    {
        double scale = 1.0;
        System.IO.MemoryStream ms = new MemoryStream(image);
        System.Drawing.Image img = System.Drawing.Image.FromStream(ms);

        double sX, sY;
        sX = width / img.Width;
        sY = height / img.Height;

        ms.Close();
        ms.Dispose();
        ms = null;
        img.Dispose();
        img = null;

        //we have the scale and the 64bit string.
        scale = Math.Min(sX, sY);
        return scale;
    }
    catch (Exception ex)
    {
        throw new Exception("Error geting scale", ex);
    }
}

I’m passing in the byte[] and the width / height that I want. After I get the scale needed, I scale the image:

public Image ScaleByPercent(Image image, float percent)
{
    try
    {
        Bitmap result = null;

        if (image != null)
        {



            int destWidth = (int)((float)image.Width * percent);
            int destHeight = (int)((float)image.Height * percent);

            Rectangle srcRec = new Rectangle(0, 0, image.Width, image.Height);
            Rectangle destRec = new Rectangle(0, 0, destWidth, destHeight);

            result = new Bitmap(destWidth, destHeight);
            result.SetResolution(image.HorizontalResolution, image.VerticalResolution);

            using (Graphics g = Graphics.FromImage(result))
            {
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;//InterpolationMode.HighQualityBicubic;
                g.DrawImage(image, destRec, srcRec, GraphicsUnit.Pixel);
            }
        }

        return result;
    }
    catch (Exception ex)
    {
        throw new Exception("Error scaling image", ex);
    }
}

public byte[] ScaleByPercent(byte[] image, float percent)
{
    try
    {
        System.IO.MemoryStream ms = new MemoryStream(image);
        System.Drawing.Image img = System.Drawing.Image.FromStream(ms);
        Image i = ScaleByPercent(img, percent);

        MemoryStream m = new MemoryStream();
        i.Save(m, System.Drawing.Imaging.ImageFormat.Png);
        image = m.ToArray();

        m.Close();
        ms.Close();
        ms.Dispose();
        m.Dispose();
        m = null;
        ms = null;
        img = null;
        i = null;
        return image;
    }
    catch (Exception ex)
    {
        throw new Exception("Error scaling image", ex);
    }
}

 

And that’s pretty much it.

More Posts