Reputation: 10542
Hey all, i am in need of some help with keeping an image aspect ratio in check. This is the aspx code that i have to resize and upload an image the user selects.
<%@ Page Trace="False" Language="vb" aspcompat="false" debug="true" validateRequest="false"%>
<%@ Import Namespace=System.Drawing %>
<%@ Import Namespace=System.Drawing.Imaging %>
<%@ Import Namespace=System %>
<%@ Import Namespace=System.Web %>
<SCRIPT LANGUAGE="VBScript" runat="server">
const Lx = 500 ' max width for thumbnails
const Ly = 60 ' max height for thumbnails
const upload_dir = "/uptest/" ' directory to upload file
const upload_original = "sample" ' filename to save original as (suffix added by script)
const upload_thumb = "thumb" ' filename to save thumbnail as (suffix added by script)
const upload_max_size = 512 ' max size of the upload (KB) note: this doesn't override any server upload limits
dim fileExt ' used to store the file extension (saves finding it mulitple times)
dim newWidth, newHeight as integer ' new width/height for the thumbnail
dim l2 ' temp variable used when calculating new size
dim fileFld as HTTPPostedFile ' used to grab the file upload from the form
Dim originalimg As System.Drawing.Image ' used to hold the original image
dim msg ' display results
dim upload_ok as boolean ' did the upload work ?
</script>
<%
randomize() ' used to help the cache-busting on the preview images
upload_ok = false
if lcase(Request.ServerVariables("REQUEST_METHOD"))="post" then
fileFld = request.files(0) ' get the first file uploaded from the form (note:- you can use this to itterate through more than one image)
if fileFld.ContentLength > upload_max_size * 1024 then
msg = "Sorry, the image must be less than " & upload_max_size & "Kb"
else
try
originalImg = System.Drawing.Image.FromStream(fileFld.InputStream)
' work out the width/height for the thumbnail. Preserve aspect ratio and honour max width/height
' Note: if the original is smaller than the thumbnail size it will be scaled up
if originalImg.Height > Ly then
newWidth = Ly * (originalImg.Width / originalImg.Height)
newHeight = Ly
end if
Dim thumb As New Bitmap(newWidth, newHeight)
'Create a graphics object
Dim gr_dest As Graphics = Graphics.FromImage(thumb)
' just in case it's a transparent GIF force the bg to white
dim sb = new SolidBrush(System.Drawing.Color.White)
gr_dest.FillRectangle(sb, 0, 0, thumb.Width, thumb.Height)
'Re-draw the image to the specified height and width
gr_dest.DrawImage(originalImg, 0, 0, thumb.Width, thumb.Height)
try
fileExt = System.IO.Path.GetExtension(fileFld.FileName).ToLower()
originalImg.save(Server.MapPath(upload_dir & upload_original & fileExt), originalImg.rawformat)
thumb.save(Server.MapPath(upload_dir & upload_thumb & fileExt), originalImg.rawformat)
msg = "Uploaded " & fileFld.FileName & " to " & Server.MapPath(upload_dir & upload_original & fileExt)
upload_ok = true
catch
msg = "Sorry, there was a problem saving the image."
end try
' Housekeeping for the generated thumbnail
if not thumb is nothing then
thumb.Dispose()
thumb = nothing
end if
catch
msg = "Sorry, that was not an image we could process."
end try
end if
' House Keeping !
if not originalImg is nothing then
originalImg.Dispose()
originalImg = nothing
end if
end if
%>
What i am looking for is a way to just have it go by the height of what i set it:
const Ly = 60 ' max height for thumbnails
And have the code for the width just be whatever. So if i had an image... say 600 x 120 (w h) and i used photoshop to change just the height, it would keep it in ratio and have it 300 x 60 (w x h). Thats what i am looking to do with this code here. However, i can not think of a way to do this (or to just leave a wildcard for the width setting.
Any help would be great :o)
David
Upvotes: 0
Views: 2447
Reputation: 16468
Actually, you need to compare the aspect ratios. Comparing height doesn't tell you which dimension is relatively the longest - sorry dingle_thunk.
if (Ly / Lx) > oldImage.Height / oldImage.Width then
newWidth = Ly * (oldImage.Width / oldImage.Height)
newHeight = Ly
else if
newWidth = Lx
newHeight = Lx * (oldImage.Height / oldImage.Width)
end if
Also, it's best to use a Using clause instead of calling .Dispose. Any number of exceptions out of your control can cause the code to stop executing, leaving the GDI handles and allocated memory undisposed.
.NET does not garbage collect them properly, which is why MS says System.Drawing is unsupported in ASP.NET.
Also, you should set the Interpolation mode on the graphics object to get the best quality:
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
And last, bitmap.Save() does a terrible job of encoding images by default. It only works properly with 32-bit PNG images. You need to specify encoder parameters for Jpegs, and quantize the bitmap before saving it as a GIF image.
See 30 Image Resizing pitfalls for the full list...
Also, you may consider using a popular free library instead, if you'd like to support more image formats and reduce your code to a single line:
ImageBuilder.Current.Build(fileFld, Server.MapPath(upload_dir & upload_original & fileExt), new ResizeSettings("maxwidth=500&maxheight=50&bgcolor=white"));
Upvotes: 1
Reputation: 906
Couldn't you just replace that whole if/else/endif block with something along these lines?
if oldImage.Height > Ly then
newWidth = Ly * (NewImage.Width / NewImage.Height)
newHeight = Ly
end if
Upvotes: 1