First have a look at my post for how to make an Images Handler. And from there, let’s continue.
The idea is that if I request something like these:
- http://localhost:54086/images/v/?img=500667&w=540
- http://localhost:54086/images/v/?img=500667&h=200
- http://localhost:54086/images/v/?img=500667&w=540&maxh=90
- http://localhost:54086/images/v/?img=500667&w=540&h=200&maxh=90&maxw=100
It will resize my image to the size I set and also, it will check the size limit for heights or widths so the resulting resized image doesn’t break our layout.
Adding some params to resize the image
Lets add the querystring params to the handler:
public const String PARAM_WIDTH = "w"; public const String PARAM_HEIGHT = "h"; public const String PARAM_MAXWIDTH = "maxw"; public const String PARAM_MAXHEIGHT = "maxh";
And a condition method:
private Boolean NeedsToBeResized(Image img) { // If one of the params comes most probably Ill need to resize: if (request.QueryString[PARAM_WIDTH] != null) { return true; } if (request.QueryString[PARAM_HEIGHT] != null) { return true; } if (request.QueryString[PARAM_MAXWIDTH] != null) { return true; } if (request.QueryString[PARAM_MAXHEIGHT] != null) { return true; } return false; }
Resizing the image
Returning a resized Image Method
private void ReturnResizedImage(Image img, String filename) { try { // Getting params from querystring: Size newSize = new Size(0, 0); Size maxSize = new Size(0, 0); if (request.QueryString[PARAM_WIDTH] != null) { newSize.Width = int.Parse(request.QueryString[PARAM_WIDTH]); } if (request.QueryString[PARAM_HEIGHT] != null) { newSize.Height = int.Parse(request.QueryString[PARAM_HEIGHT]); } if (request.QueryString[PARAM_MAXWIDTH] != null) { maxSize.Width = int.Parse(request.QueryString[PARAM_MAXWIDTH]); } if (request.QueryString[PARAM_MAXHEIGHT] != null) { maxSize.Height = int.Parse(request.QueryString[PARAM_MAXHEIGHT]); } img = resizeImage(img, CalculateNewSize(img, newSize, maxSize)); img.Save(HttpContext.Current.Response.OutputStream, getFormat(filename)); } catch (Exception e) { response.StatusCode = 400; response.Write("Bad request."); } }
Checking the new size for the image
private static Size CalculateNewSize(Image img, Size newSize, Size max) { float nPercent = 1; float nPercentW = 1; float nPercentH = 1; // STEP 1. RESIZE TO FIX SIZES if (newSize.Width > 0 && newSize.Height > 0) { // The smaller gets priority: if (img.Width != newSize.Width) nPercentW = ((float)newSize.Width / (float)img.Width); if (img.Height != newSize.Height) nPercentH = ((float)newSize.Height / (float)img.Height); if (nPercentH < nPercentW) { nPercent = nPercentH; } else { nPercent = nPercentW; } } else if (newSize.Width > 0) { nPercent = ((float)newSize.Width / (float)img.Width); } else if (newSize.Height > 0) { nPercent = ((float)newSize.Height / (float)img.Height); } // Calculate new sizes: int resWidth = (int)(img.Width * nPercent); int resHeight = (int)(img.Height * nPercent); // ================================== // STEP 2. CHECK THE LIMITS if (max.Width > 0 && resWidth > max.Width) { nPercent = ((float)max.Width / (float)resWidth); resWidth = (int)(resWidth * nPercent); resHeight = (int)(resHeight * nPercent); } if (max.Height > 0 && resHeight > max.Height) { nPercent = ((float)max.Height / (float)resHeight); resWidth = (int)(resWidth * nPercent); resHeight = (int)(resHeight * nPercent); } return new Size(resWidth, resHeight); }
Resizing the Image, simple way
private static Image resizeImage(Image imgToResize, Size size) { if (imgToResize.Width != size.Width || imgToResize.Height != size.Height) { return new Bitmap(imgToResize, size.Width, size.Height); } else { return imgToResize; } }
Getting the format type
Unfortunately, to send the image to the client in the response we need to know its format type, which we can know in various ways like checking the image filename extension or getting its mimetype. Affortunately, both of us were saved in the db:
private static System.Drawing.Imaging.ImageFormat getFormat(String MimeType) { switch (MimeType.ToLower()) { case "image/jpeg": case "image/jpg": return System.Drawing.Imaging.ImageFormat.Jpeg; case "image/gif": return System.Drawing.Imaging.ImageFormat.Gif; case "image/png": return System.Drawing.Imaging.ImageFormat.Png; default: return System.Drawing.Imaging.ImageFormat.Bmp; } }
In case you prefer to use the filename:
private static System.Drawing.Imaging.ImageFormat getFormat(String name) { switch (System.IO.Path.GetExtension(name).ToLower()) { case ".jpeg": case ".jpg": return System.Drawing.Imaging.ImageFormat.Jpeg; case ".gif": return System.Drawing.Imaging.ImageFormat.Gif; case ".png": return System.Drawing.Imaging.ImageFormat.Png; default: return System.Drawing.Imaging.ImageFormat.Bmp; } }
The new Image Handler ProcessRequest
public void ProcessRequest(HttpContext context) { request = context.Request; response = context.Response; List<SqlParameter> pl = new List<SqlParameter>(); pl.Add(new SqlParameter("imgId", request.QueryString["img"])); IDataReader dr = MyNamespace.db.getReader("sp_getImage", pl); if (dr != null && dr.Read()) { context.Response.ContentType = dr["mimeType"].ToString(); MemoryStream ms = new MemoryStream((byte[])dr["image"]); Image img = System.Drawing.Image.FromStream(ms); if (!NeedsToBeResized(img)) { //Display directly from db: context.Response.BinaryWrite((byte[])dr["image"]); } else { ReturnResizedImage(img, dr["fileName"].ToString()); } } else { response.StatusCode = 404; response.Write("Not found."); } }
Finally, putting all of it together:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Data; using System.Data.SqlClient; using System.IO; using System.Drawing; using System.Drawing.Imaging; namespace MyNamespace { public class VirtualImagesHandler : IHttpHandler { private HttpRequest request = null; private HttpResponse response = null; public const String PARAM_WIDTH = "w"; public const String PARAM_HEIGHT = "h"; public const String PARAM_MAXWIDTH = "maxw"; public const String PARAM_MAXHEIGHT = "maxh"; public bool IsReusable { get { return true; } } public void ProcessRequest(HttpContext context) { request = context.Request; response = context.Response; // // TODO: Check if user has rights to access this image. // List<SqlParameter> pl = new List<SqlParameter>(); pl.Add(new SqlParameter("imgId", request.QueryString["img"])); IDataReader dr = MyNamespace.db.getReader("sp_getImage", pl); if (dr != null && dr.Read()) { context.Response.ContentType = dr["mimeType"].ToString(); MemoryStream ms = new MemoryStream((byte[])dr["image"]); Image img = System.Drawing.Image.FromStream(ms); if (!NeedsToBeResized(img)) { //Display directly from db: context.Response.BinaryWrite((byte[])dr["image"]); } else { ReturnResizedImage(img, dr["fileName"].ToString()); } } else { response.StatusCode = 404; response.Write("Not found."); } } private Boolean NeedsToBeResized(Image img) { // If one of the params comes most probably Ill need to resize: if (request.QueryString[PARAM_WIDTH] != null) { return true; } if (request.QueryString[PARAM_HEIGHT] != null) { return true; } if (request.QueryString[PARAM_MAXWIDTH] != null) { return true; } if (request.QueryString[PARAM_MAXHEIGHT] != null) { return true; } return false; } private void ReturnResizedImage(Image img, String filename) { try { // Getting params from querystring: Size newSize = new Size(0, 0); Size maxSize = new Size(0, 0); if (request.QueryString[PARAM_WIDTH] != null) { newSize.Width = int.Parse(request.QueryString[PARAM_WIDTH]); } if (request.QueryString[PARAM_HEIGHT] != null) { newSize.Height = int.Parse(request.QueryString[PARAM_HEIGHT]); } if (request.QueryString[PARAM_MAXWIDTH] != null) { maxSize.Width = int.Parse(request.QueryString[PARAM_MAXWIDTH]); } if (request.QueryString[PARAM_MAXHEIGHT] != null) { maxSize.Height = int.Parse(request.QueryString[PARAM_MAXHEIGHT]); } img = resizeImage(img, CalculateNewSize(img, newSize, maxSize)); img.Save(HttpContext.Current.Response.OutputStream, getFormat(response.ContentType)); } catch (Exception e) { response.StatusCode = 400; response.Write("Bad request."); } } private static System.Drawing.Imaging.ImageFormat getFormat(String MimeType) { switch (MimeType.ToLower()) { case "image/jpeg": case "image/jpg": return System.Drawing.Imaging.ImageFormat.Jpeg; case "image/gif": return System.Drawing.Imaging.ImageFormat.Gif; case "image/png": return System.Drawing.Imaging.ImageFormat.Png; default: return System.Drawing.Imaging.ImageFormat.Bmp; } } private static Image resizeImage(Image imgToResize, Size size) { if (imgToResize.Width != size.Width || imgToResize.Height != size.Height) { return new Bitmap(imgToResize, size.Width, size.Height); } else { return imgToResize; } } private static Size CalculateNewSize(Image img, Size newSize, Size max) { float nPercent = 1; float nPercentW = 1; float nPercentH = 1; // STEP 1. RESIZE TO FIX SIZES if (newSize.Width > 0 && newSize.Height > 0) { // The smaller gets priority: if (img.Width != newSize.Width) nPercentW = ((float)newSize.Width / (float)img.Width); if (img.Height != newSize.Height) nPercentH = ((float)newSize.Height / (float)img.Height); if (nPercentH < nPercentW) { nPercent = nPercentH; } else { nPercent = nPercentW; } } else if (newSize.Width > 0) { nPercent = ((float)newSize.Width / (float)img.Width); } else if (newSize.Height > 0) { nPercent = ((float)newSize.Height / (float)img.Height); } // Calculate new sizes: int resWidth = (int)(img.Width * nPercent); int resHeight = (int)(img.Height * nPercent); // ================================== // STEP 2. CHECK THE LIMITS if (max.Width > 0 && resWidth > max.Width) { nPercent = ((float)max.Width / (float)resWidth); resWidth = (int)(resWidth * nPercent); resHeight = (int)(resHeight * nPercent); } if (max.Height > 0 && resHeight > max.Height) { nPercent = ((float)max.Height / (float)resHeight); resWidth = (int)(resWidth * nPercent); resHeight = (int)(resHeight * nPercent); } return new Size(resWidth, resHeight); } public static String getImageURL(int ImageID) { return SkyGuard.CSC.Config.PATH_VIRTUALIMGFOLDER + "?img=" + ImageID; } public static String getImageURL(int ImageID, ImageSizes sizes) { String url = SkyGuard.CSC.Config.PATH_VIRTUALIMGFOLDER + "?img=" + ImageID; if (sizes.Width > 0) { url += "&" + PARAM_WIDTH + "=" + sizes.Width.ToString(); } if (sizes.Height > 0) { url += "&" + PARAM_HEIGHT + "=" + sizes.Height.ToString(); } if (sizes.MaxWidth > 0) { url += "&" + PARAM_MAXWIDTH + "=" + sizes.MaxWidth.ToString(); } if (sizes.MaxHeight > 0) { url += "&" + PARAM_MAXHEIGHT + "=" + sizes.MaxHeight.ToString(); } return url; } public class ImageSizes { public int Width { get; set; } public int Height { get; set; } public int MaxWidth { get; set; } public int MaxHeight { get; set; } public ImageSizes() : this(-1, -1, -1, -1) { } public ImageSizes(int pWidth, int pHeight) { if (pWidth > 0) Width = pWidth; if (pHeight > 0) Height = pHeight; MaxHeight = -1; MaxWidth = -1; } public ImageSizes(int pWidth, int pHeight, int pMaxWidth, int pMaxHeight) { if (pWidth > 0) Width = pWidth; if (pHeight > 0) Height = pHeight; if (pMaxWidth > 0) MaxWidth = pMaxWidth; if (pMaxHeight > 0) MaxHeight = pMaxHeight; } } } }