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>


11 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????

Rufan-Redi 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,

Rufan-Redi 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.

İstanbulgöz Hastanesi said...

This script is awesome.

But didnt work in update panel of ajax.

this script is work well in ie6 and ff and opera

otavio 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.