Sunday, October 10, 2010

Image Handling in Asp.net

This article discuss about Image Handling, which in turns become important while handling high resolution images and displaying them in different sizes. Especially in case of E-commerce web applications, where admin can add different images of the same product so that users can get feel of the products. Also for image galleries where we need display same image in different sizes with zoom in and zoom out options.
For above requirement following points should be considered
  • Image should not distorted when re-sized.
  • Quality of the image should remain same.
  • If image is of High resolution then while displaying image is different sizes; the image which loads in browser should be of relative size. E.g. suppose image resolution is of 2736x3648, and we resize such high resolution image in the size of 200x300, then the new small image should be of relative size, i.e. original image size is 3.34MB then while displaying in small size it should be reduced as per size.
  • All images displayed in browser should be of same time, i.e. user can upload images like JPEG, JPG, BMP, TIFF etc. and while displaying all images should be displayed in PNG format only.
  • End user should be able save image of size which he/she is able to see in browser. i.e. if browser is showing image with 200x300 size; user can save image by right clicking it, then the image which is getting saved should be of the 200x300 size only.
Download DemoCode for better understanding of this article, you can also get to debug code while reading the article.
The main file for all above operations is ImageHandler.ashx, its a http handler file, in that file following function takes care of resizing of image, just check it out.
private Image ResizeImage(Image img, int maxWidth, int maxHeight)
    {
        if (img.Height < maxHeight && img.Width < maxWidth) return img;
        Double xRatio = (double)img.Width / maxWidth;
        Double yRatio = (double)img.Height / maxHeight;
        Double ratio = Math.Max(xRatio, yRatio);
        int NewX = (int)Math.Floor(img.Width / ratio);
        int NewY = (int)Math.Floor(img.Height / ratio);
        Bitmap imgCopy = new Bitmap(NewX, NewY, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
        Graphics graphicsImg = Graphics.FromImage(imgCopy);
        graphicsImg.Clear(Color.Transparent);
        graphicsImg.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
        //HighQualityBicubic gives best quality when resizing images
        graphicsImg.DrawImage(img,
            new Rectangle(0, 0, NewX, NewY),
            new Rectangle(0, 0, img.Width, img.Height),
            GraphicsUnit.Pixel);
        graphicsImg.Dispose();
        img.Dispose();
        return imgCopy;
    }
Above function takes care of re-sizing of image, this function simply maintains the quality of image, and if image which we are re-sizing is less than in size than that we are asking for, this function simply returns the image. To avoid distortion of image on re-sizing we have maintained aspect ratio too.
We are using ashx file as query string in Image source, which picks up image and render it in desired size code is as below.

So remaining code of our Ashx file is as below
string sImageFileName = "";
    string imageSize = "";
    int oldHeight, oldWidth, NewHeight, NewWidth;

    System.Drawing.Image objImage;
    
    public void ProcessRequest (HttpContext context)
    {
        sImageFileName = context.Request.QueryString["img"];
        imageSize = Convert.ToString(context.Request.QueryString["sz"]);

        if (imageSize == "Small") NewHeight = 50;
        else if (imageSize == "Thumb") NewHeight = 160;
        else if (imageSize == "Medium") NewHeight = 320;
        else if (imageSize == "Large") NewHeight = 640;
        
        objImage = System.Drawing.Bitmap.FromFile(System.Web.HttpContext.Current.Server.MapPath("Images//" + sImageFileName));

        oldHeight = objImage.Height;
        oldWidth = objImage.Width;
        NewWidth = oldWidth * (NewHeight / oldHeight);

        objImage = ResizeImage(objImage, oldHeight, NewHeight);

        MemoryStream objMemoryStream = new MemoryStream();
        objImage.Save(objMemoryStream, System.Drawing.Imaging.ImageFormat.Png);
        byte[] imageContent = new byte[objMemoryStream.Length];
        objMemoryStream.Position = 0;
        objMemoryStream.Read(imageContent, 0, (int)objMemoryStream.Length);

        context.Response.BinaryWrite(imageContent);
    }
 
    public bool IsReusable
    {
        get 
        {
            return false;
        }
    }

 
    private bool callback()
    {
        return true;
    }

We have developed logic for image handling in mainly two files one is web user control i.e. webImageGallery.ascx and another is ImageHandler.ashx.
Check out folder structure of the democode.
Following Html code of imgGallery.ascx is, do refer democode.
We have one function in imgGallery.ascx.cs file, which builds gallery kind of logic is named CreateImages(), and its code is as below, you can put your own logic for creating image gallery the way you want, I tired to keep logic simple. Once you build do solution check out source code of the gallery. Its simple JavaScript which changes image source on click on thumb image.
protected void CreateImages()
    {
        int Count = 0;
        HtmlTableRow _htmlTableRow = new HtmlTableRow();
        _ProductTable.Rows.Add(_htmlTableRow);

        Directory.SetCurrentDirectory(imagePath);

        for (Count = 1; Count <= imageCount; Count++)
        {
            HtmlTableCell _htmlTableTd = new HtmlTableCell();
            _htmlTableRow.Cells.Add(_htmlTableTd);
            _htmlTableTd.Align = Convert.ToString(setImageAlign);
            Image _ThumbImage = new Image();
            _htmlTableTd.Controls.Add(_ThumbImage);
            if (Convert.ToString(setBorder) == "True")
            {
                _ThumbImage.BorderStyle = BorderStyle.Solid;
                _ThumbImage.BorderWidth = 1;
            }
            _ThumbImage.ID = ThumbImageName + Count;
            _ThumbImage.ImageUrl = "ImageHandler.ashx?img=" + imageNames[Count - 1] + "&sz=" + Convert.ToString(setThumbImageSize);
            _ThumbImage.Attributes.Add("onclick", "javascript:ImageButton_OnClientClick('" + _mainImage.ClientID + "','" + imageNames[Count - 1] + "','" + setMainImageSize + "');");
        }

        _mainImage.ImageUrl = "ImageHandler.ashx?img=" + imageNames[imageCount - (Count-1)] + "&sz=" + Convert.ToString(setMainImageSize);
    }
Please check out variables in DemoCode, they are simply used as properties.
Once websuercontrol is ready, we simply drag and drop it in Default.aspx page and set following properties of the imageGallery web user control.
protected void Page_Load(object sender, EventArgs e)
    {
        ImageGallary.ImagePath = Server.MapPath("Images");
        ImageGallary.ImageNames = new string[] { "1_1.JPG", "1_2.JPG", "1_3.JPG", "1_4.JPG", "1_5.JPG" };
        ImageGallary.ImageCount = ImageGallary.ImageNames.Length;
        ImageGallary.SetImageAlign = _ImageAlign.Left;
        ImageGallary.SetMainImageSize = _ImageSize.Medium;
        ImageGallary.SetThumbImageSize = _ImageSize.Small;
        ImageGallary.SetBorder = _Border.True;
    } 
Download Democode here---> ImageUserControl.zip
Submit this story to DotNetKicks

0 comments: