Wednesday, September 07, 2005

Upload and resize an image with ASP.NET (VB.NET)

A while ago I needed to create a function to allow a user to upload an image and have the system resize it to a thumbnail - preserving the aspect ratio, while at the same time ensuring that neither of the maximum constraints of the thumbnail width or height where breached - and then save it to the server.

The function had to be written for an ASP.NET server and ideally in VBScript to fit in with the rest of the project. To further complicate matters it was a hybrid project... a halfway house in a migration from Classic ASP to dot Net.

I did the usual trawl around Google looking for code fragments to base the function on and to my surprise almost every one of them ended up producing either terrible quality thumbnails (relying on the .net GetThumbnailImage function) or huge filesizes. It was only as a result of a lot more diligent searching that I was able to solve the latter problem and so I thought I'd share it.

You can either click to go to a working sample, with source online and in a zip file or just grab the source from here and play....


If you think this has saved you time, effort and storage space, maybe you'd like to

  1: <%@ Page Trace="False" Language="vb" aspcompat="false" debug="true" validateRequest="false"%>
2:
<%@ Import Namespace=System.Drawing %>
3:
<%@ Import Namespace=System.Drawing.Imaging %>
4:
<%@ Import Namespace=System %>
5:
<%@ Import Namespace=System.Web %>
6: <SCRIPT LANGUAGE="VBScript" runat="server">
7: const Lx = 200 ' max width for thumbnails
8: const Ly = 240 ' max height for thumbnails
9: const upload_dir = "/upload_resize_test/" ' directory to upload file
10: const upload_original = "sample" ' filename to save original as (suffix added by script)
11: const upload_thumb = "thumb" ' filename to save thumbnail as (suffix added by script)
12: const upload_max_size = 25 ' max size of the upload (KB) note: this doesn't override any server upload limits
13: dim fileExt ' used to store the file extension (saves finding it mulitple times)
14: dim newWidth, newHeight as integer ' new width/height for the thumbnail
15: dim l2 ' temp variable used when calculating new size
16: dim fileFld as HTTPPostedFile ' used to grab the file upload from the form
17: Dim originalimg As System.Drawing.Image ' used to hold the original image
18: dim msg ' display results
19: dim upload_ok as boolean ' did the upload work ?
20: </script>
21:
<%
22: randomize() ' used to help the cache-busting on the preview images
23:
upload_ok = false
24: if lcase(Request.ServerVariables("REQUEST_METHOD"))="post" then
25: fileFld = request.files(0) ' get the first file uploaded from the form (note:- you can use this to itterate through more than one image)
26:
if fileFld.ContentLength > upload_max_size * 1024 then
27: msg = "Sorry, the image must be less than " & upload_max_size & "Kb"
28: else
29: try
30: originalImg = System.Drawing.Image.FromStream(fileFld.InputStream)
31: ' work out the width/height for the thumbnail. Preserve aspect ratio and honour max width/height
32:
' Note: if the original is smaller than the thumbnail size it will be scaled up
33:
If (originalImg.Width/Lx) > (originalImg.Width/Ly) Then
34: L2 = originalImg.Width
35: newWidth = Lx
36: newHeight = originalImg.Height * (Lx / L2)
37: if newHeight > Ly then
38: newWidth = newWidth * (Ly / newHeight)
39: newHeight = Ly
40: end if
41: Else
42: L2 = originalImg.Height
43: newHeight = Ly
44: newWidth = originalImg.Width * (Ly / L2)
45: if newWidth > Lx then
46: newHeight = newHeight * (Lx / newWidth)
47: newWidth = Lx
48: end if
49: End If
50:
51: Dim thumb As New Bitmap(newWidth, newHeight)
52:
53: 'Create a graphics object
54:
Dim gr_dest As Graphics = Graphics.FromImage(thumb)
55:
56: ' just in case it's a transparent GIF force the bg to white
57:
dim sb = new SolidBrush(System.Drawing.Color.White)
58: gr_dest.FillRectangle(sb, 0, 0, thumb.Width, thumb.Height)
59:
60: 'Re-draw the image to the specified height and width
61:
gr_dest.DrawImage(originalImg, 0, 0, thumb.Width, thumb.Height)
62:
63: try
64: fileExt = System.IO.Path.GetExtension(fileFld.FileName).ToLower()
65: originalImg.save(Server.MapPath(upload_dir & upload_original & fileExt), originalImg.rawformat)
66: thumb.save(Server.MapPath(upload_dir & upload_thumb & fileExt), originalImg.rawformat)
67: msg = "Uploaded " & fileFld.FileName & " to " & Server.MapPath(upload_dir & upload_original & fileExt)
68: upload_ok = true
69: catch
70: msg = "Sorry, there was a problem saving the image."
71: end try
72: ' Housekeeping for the generated thumbnail
73:
if not thumb is nothing then
74: thumb.Dispose()
75: thumb = nothing
76: end if
77: catch
78: msg = "Sorry, that was not an image we could process."
79: end try
80: end if
81:
82: ' House Keeping !
83:
if not originalImg is nothing then
84: originalImg.Dispose()
85: originalImg = nothing
86: end if
87:
88: end if
89: %>
90: <html>
91: <head>
92: <title>ASP.NET File Upload and Resize Sample</title>
93: <META NAME="Description" CONTENT="ASP.NET File Upload and Resize Sample (Hybrid VB.NET)">
94: <META NAME="Keywords" CONTENT="ASP.NET, ASP, NET, VB, VBScript, Image, Upload, Resize, Thumbnail, Constrain, Filesize, File, Size, Free">
95: <META NAME="Copyright" CONTENT="Rufan-Redi Pty Ltd 2005">
96: <META NAME="Author" CONTENT="System developed by Jeremy at http://www.Rufan-Redi.com">
97: </head>
98: <body>
99:
100: <p><b>Hybrid ASP.NET File Upload and Resize Sample (VB.NET)</b>
101: <br>Upload and resize a GIP/JPG/PNG images, ensuring filesizes are optimum.</p>
102:
103: <form enctype="multipart/form-data" method="post" runat="server">
104: <table>
105: <tr><td>Select the file to upload:</td><td><input type="file" name="upload_file"></td></tr>
106: <tr><td colspan=2>Max upload size
<%=upload_max_size%>Kb, gif/jpg/png only</td></tr>
107: <tr><td colspan=2><input type="submit" value="Upload"></td></tr>
108: </table>
109: </form>
110:
111:
<%
112: if upload_ok then
113: %>
114: <table>
115: <tr>
116: <td valign=top><img src="
<%=upload_dir & upload_original & fileExt & "?" & rnd()%>"></td>
117: <td valign=top><img src="
<%=upload_dir & upload_thumb & fileExt & "?" & rnd()%>"></td>
118: </tr>
119: </table>
120:
<%
121: else
122: response.write(msg)
123: end if
124: %>
125: </body>
126: </html>


26 comments:

Anonymous said...

This is an awesome script. However I cant get it to work in IE 6....but it works in firefox just fine. No errors just doesnt save the file to the server in IE 6????

Offbeatmammal said...

hmmm. weird. I've tested the sample version (linked from the post) in IE6, IE7 and FF (and Safari as well) and not had any problem.
The version in the script is limited to 25kb uploads.
if you're still stuck hop over to http://www.rufan-redi.com/contact.php and say Hi and I'll see if we can track the problem down...

Anonymous said...

Doesn't work with animated gif's :(

Anonymous said...

Doesn't work for me "Cant save file" error returned when I try to run example.

Regards,

Offbeatmammal said...

@ previous comment... do you have write permissions on the server you're trying to upload to? If the script isn't allowed to write you'll run into a problem ;)

Anonymous said...

Thank You! I've looked for over 5 hours for some nice code to only allow images to be uploaded. Thank you for your well thought out excellant code. You're a star!

Anonymous said...

I have a vb.net application accessing online DB and I need to upload an image thru vb.net(not to the DB). Is this possible and can anyone give me a sample code?

Anonymous said...

Never worked for me.

YĆ¼cel Kandemir said...

This script is awesome.

But didnt work in update panel of ajax.

this script is work well in ie6 and ff and opera

Anonymous said...

Congratulations, great job!
But I think that this script has an error at line 33.

Current code:
If (originalImg.Width / Lx) > (originalImg.Width / Ly) Then

Revision:
If (originalImg.Width / Lx) > (originalImg.Height / Ly) Then

I hope it helps. See you!

Anonymous said...

I agree with the previous posting...probably an error on line 33. Great job otherwise, will use it as a proof-of-concept that resizing a picture (either up or down) automatically can be done. Probably won't end up as production code.

Anonymous said...

Doesnt work for me...i get the following error:-

"Sorry, there was a problem saving the image.A generic error occurred in GDI+."

Anonymous said...

hey this is Manish
Thanks a ton for the script.... i seriously needed this script.... you have done a great job....

if there are other such codes using asp.net 2.0 vb i would love to go though it.....

i agree u r a star!!!

Unknown said...

Fantasic code. Worked great. Thank you

Anonymous said...

How about using a code-behind file instead of a script?

Mitchy said...

i tried this but the file size of the resized images is still very large. i am resizing to 640x480 and most image file sizes are around 400k which is way too large. have you been able to resolve this?

Mitchy said...

i resolved the problem by using the orignal images rawformat as you have done. this brought the file size down considerably. thanks for your help. great work.

AMR said...

hi, nice script. could you pleaes explain how to get this working for multiple images? i have 15 image boxes. also, i need to keep the original filenames. is this possible? many thanks

Anonymous said...

Amazing script. If you want to use within update panel you have to allow a full postback when you click the upload button; i.e., create a full postback trigger within the update panel using the upload button as the trigger.

Thanks again!

pcano@inducosoft.com

Anonymous said...

hi.
Date of this post is September 07, 2005. And I'm writing on February 02, 2009. This script is fabulous. Thanks for sharing it. I'll be using it in most of my projects. By the way, the only problem I got is the server mappath which is completely related with my own server/hosting. Check your mappath and directory permissions if you got any error. This should work for all using asp.net. It's clean, simple and perfect. Thanks for sharing !

Anonymous said...

I use this asp.net webcontrol:

http://i-load.radactive.com/en/

it saved me a lot of time.

Regards
Markus

Hasan said...

I have an error:
A generic error occurred in GDI+.
System.Drawing
at System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams) at System.Drawing.Image.Save(String filename, ImageFormat format) at ASP.at_ur_aspx.__Render__control1(HtmlTextWriter __w, Control parameterContainer) in C:\WebSites\ur.aspx:line 65

RRave said...

Invitation to new programming Resources Website



Dear Sir,

I hope you are doing well. I got this email address from one of your contribution web site. I have launched a web site www.codegain.com and it is basically aimed C#,JAVA,VB.NET,ASP.NET,AJAX,Sql Server,Oracle,WPF,WCF and etc resources, programming help, articles, code snippet, video demonstrations and problems solving support. I would like to invite you as an author and a supporter.
Looking forward to hearing from you and hope you will join with us soon.

Thank you
RRaveen
Founder CodeGain.com

thingamajig said...

Kudos, Rufan-Redi! :)

Script worked for me, though I had to revise the directory from:
Const upload_dir = "/upload_resize_test/"
TO
Const upload_dir = "~/upload_resize_test/"
to correct the 'Failed to map the path '/upload_resize_test/sample.jpg'.' error I was getting.

Nonetheless, this is exactly what I am looking for.

-Kathy J.

David said...

Where can I view the video tutorial on this? My colleague said he viewed a tutorial on this but I can't find the link.

Thanks

(I can't get it to work)

Offbeatmammal said...

@Kathy - sounds like a permissions issue (described earlier in comments)

@David - no video tutorial. What problem/error are you having?