Thursday, January 17, 2013

Cropping an Image in C#

Explanation on how to crop an image in C#.Net

I wrote this code when I was working with my own social network site and run-through with the images problem in Web (large images were displayed late in the pages). In C# there is no built-in Class or API to be used to crop an image file or an image object. I atleast need to write my own function or class to accomplish my requirements.

In business needs, some of the images of your application were saved in the database. If you're working with the CRM or ECommerce enterprise applications and systems, this scenario is very common. With this technique, before you upload the image in the database, you should resize it first to a small one.

I'll explain in detail how are we going to accomplish it.

Explanation

When you have your file converted to an object Image (of System.Drawing namespace) in C#, then you can do anything with the help of Bitmap class and other image related classes. In .NET 4.0, the class Bitmap (of System.Drawing namespace) will do the job.

First, you need to create an image from a file (or you can create with your own). The FromFile method of Image class will load the image file from the file system. See the codes below.

var filename = @"c:\personal\images\horizon.png";
var img = Image.FromFile(filename);

After you have loaded the image, use the Bitmap class to crop the Image object. Cloning an image via Bitmap class will require an argument of Rectangle and PixelFormat. It depends on your desire size, you can pass it as an argument value in the Rectangle Size.

var rect = new Rectangle(new Point(0, 0), img.Size);
var cloned = new Bitmap(img).Clone(rect, img.PixelFormat);

After cloning, you have your option to create another Bitmap object and set your desired size there. Then dispose the cloned object. See below the code.

var bitmap = new Bitmap(cloned, new Size(50, 50));
cloned.Dispose();

The code above shows you how to do the actual cropping.

My Class Implementation

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Drawing;

namespace CodesDirectory
{
    public static class ImageUtility
    {
        public static Image Crop(Image image, int height, int width)
        {
            if (object.ReferenceEquals(image, null)) throw new NullReferenceException("Image");
            var squareLength = image.Width < image.Height ? image.Width : image.Height;
            var top = 0;
            var left = 0;
            if (image.Width > image.Height)
            {
                left = (image.Width / 2) - (image.Height / 2);
                top = 0;
            }
            else
            {
                left = 0;
                top = (image.Height / 2) - (image.Width / 2);
            }
            var rect = new Rectangle(new Point(left, top), new Size(squareLength, squareLength));
            var cloned = new Bitmap(image).Clone(rect, image.PixelFormat);
            var bitmap = new Bitmap(cloned, new Size(width, height));
            cloned.Dispose();
            return bitmap;
        }

        public static Image CropRatio(Image image, int max)
        {
            if (object.ReferenceEquals(image, null)) throw new NullReferenceException("Image");
            double ratio = image.Height > image.Width ? (double)image.Width / (double)image.Height : (double)image.Height / (double)image.Width;
            double height = 0;
            double width = 0;
            if (image.Height > image.Width)
            {
                height = image.Height > max ? max : image.Height;
                width = height * ratio;
            }
            else
            {
                width = image.Width > max ? max : image.Width;
                height = width * ratio;
            }
            var rect = new Rectangle(new Point(0, 0), new Size(image.Width, image.Height));
            var cloned = new Bitmap(image).Clone(rect, image.PixelFormat);
            var bitmap = new Bitmap(cloned, new Size((int)width, (int)height));
            cloned.Dispose();
            return bitmap;
        }

        public static System.Boolean IsValidImage(string filename)
        {
            try
            {
                var bitmap = new Bitmap(filename);
                bitmap.Dispose();
                return true;
            }
            catch
            {
            }
            return false;
        }

        public static System.Boolean IsValidImage(Stream stream)
        {
            try
            {
                var bitmap = new Bitmap(stream);
                bitmap.Dispose();
                return true;
            }
            catch
            {
            }
            return false;
        }
    }
}

Now we just finish the job cropping of image.

2 comments:

  1. I'm on the fence about this, while more customization is good, I have a feeling this is a "in-progress" update, it just feels incomplete and half-way there.
    We use badge layout for apps on design approvals (visual projects), so the image being displayed is important. Old layout "feels like" it had larger images,
    maybe because the images were cropped more loosely so it's easier to tell which project it was at quick glance. Now the image is cropped closer, making it
    harder to scan thru at quick glance. I find myself needing to click into the project more often than usual. Which makes the whole user experience less
    efficient.
    I have a couple suggestions that might make it work better:
    1. Increase the height of the window the cover image is being displayed.
    2. Let us to choose which image to be displayed as "cover" (like how Pinterest handles cover images of each board, was hoping for this for a long time)
    3. Let us adjust which part of the image to show and how tight or loose the crop is (with a fixed window, let us move the image around and maybe enlarge or
    shrink it to control what shows thru the window. Pinterest does a limited form of this, which is very useful in making the cover image relevant)
    4. Allow Cover Image to be ordered in different hierarchy (currently every element can be ordered differently except the Cover Image, it seems to be stuck
    in the 2nd spot, would like the option to set it on another spot in the layout. This one seems like an easy fix, since you guys allow that for every other
    element already)

    ReplyDelete
  2. I'm on the fence about this, while more customization is good, I have a feeling this is a "in-progress" update, it just feels incomplete and half-way there.
    We use badge layout for apps on design approvals (visual projects), so the image being displayed is important. Old layout "feels like" it had larger images,
    maybe because the images were cropped more loosely so it's easier to tell which project it was at quick glance. Now the image is cropped closer, making it
    harder to scan thru at quick glance. I find myself needing to click into the project more often than usual. Which makes the whole user experience less
    efficient.
    I have a couple suggestions that might make it work better:
    1. Increase the height of the window the cover image is being displayed.
    2. Let us to choose which image to be displayed as "cover" (like how Pinterest handles cover images of each board, was hoping for this for a long time)
    3. Let us adjust which part of the image to show and how tight or loose the crop is (with a fixed window, let us move the image around and maybe enlarge or
    shrink it to control what shows thru the window. Pinterest does a limited form of this, which is very useful in making the cover image relevant)
    4. Allow Cover Image to be ordered in different hierarchy (currently every element can be ordered differently except the Cover Image, it seems to be stuck
    in the 2nd spot, would like the option to set it on another spot in the layout. This one seems like an easy fix, since you guys allow that for every other
    element already)

    ReplyDelete

Place your comments and ideas