Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

LeftImage - An Image Optimization Library with Fluent Interface

4.57/5 (4 votes)
4 Jan 2010CPOL5 min read 33K   915  
A simple library to save, resize, scale, crop, and rotate uploaded images.

Image 1

Sample images of combined manipulations

Introduction

This library is an evolution of the Simple Image Resizing Library I wrote about in January of 2008. Working with and manipulating images has become much more common, so I developed this library to make that work much quicker and easier.

Background

This library uses a Fluent interface to make the code more readable and terse. The Fluent interface also helps to show the image optimizations that can be chained together. While this library does offer a lot of time-saving and space-saving features - there are a few things that it does not do. For example, you will need to handle validation and naming issues: is the image too big? does another image with the same name exist already? etc.

Using the code

To use the library, you will work with one of three main classes: WebImage, GenericImage, and ZipImage. WebImage should be used, of course, when working with images uploaded from a website. WebImage and GenericImage can both manipulate images directly, while ZipImage can extract images from a Zip file.

There's probably some more work to be done on this library, so suggestions and recommendations are welcome.

Example 1: Single image, single optimization

In this first example, we'll assume that we've just posted to an ASPX page, and used a FileUpload control to select an image to upload. This code is placed in the ButtonSubmit_Click method:

C#
//create WebImage from the uploaded file
var img = new WebImage(fileUploader);
//change the path, so it gets saved in the "resize" directory
img.Path = "orig";
//save the image, this returns the "PathInfo" object
//which contains the actual path information
var fullImageInfo = img.Save();

//now create manipulated versions, and save them
var resize1 = img.Resize(300, null).Save("resize", "1_" + img.FileName);
var crop1 = img.Crop(300, 300, 
    CropAnchorPosition.Center).Save("crop", "1_" + img.FileName);
var rotate1 = img.Rotate(45, Color.White).Save(
                    "rotate", "1_" + img.FileName);
var scale1 = img.Scale(90).Save("scale", "1_" + img.FileName);

//now display the images
img1.ImageUrl = resize1.OriginalPath;
img2.ImageUrl = crop1.OriginalPath;
img3.ImageUrl = rotate1.OriginalPath;
img4.ImageUrl = scale1.OriginalPath;

Now, we'll go over the example above, line by line. The first line creates a WebImage using the uploaded file. The constructor extracts the image and information, and returns a populated WebImage object.

C#
var img = new WebImage(fileUploader);

The next line sets the path to the directory "orig". This is the directory that we want to save the original uploaded file into. Please note that you must adjust the permissions on this directory to allow the .NET process to write to it.

C#
img.Path = "orig";

The next line simply calls the Save method that is available on the WebImage object. Because we didn't pass in any parameters, this method will save the uploaded image using its existing file name.

C#
var fullImageInfo = img.Save();

The next section starts with some image manipulation.

The first line takes the same WebImage object, and calls the "Resize" method, constraining only the width (the first parameter) to 300 pixels. The second parameter is for the maximum height, so passing in null will not constrain the height at all. The next call saves the image to the "resize" directory, and prepends "1_" to the filename.

Image 2

Resize result from the included sample project

The second line calls the "Crop" method, setting the width and height to 300 pixels, and cropping from the center of the image. It is then saved to the "crop" directory, with "1_" prepended to the filename.

Image 3

Crop result from the included sample project

The third line calls the "Rotate" method, setting the angle to 45, and setting the resulting background color to white. It is then saved as well using the same convention.

Image 4

Rotate result from the included sample project

The fourth line calls the "Scale" method, setting the percentage to 90. This is then also saved using the same convention.

Image 5

Scale result from the included sample project
C#
var resize1 = img.Resize(300, null).Save("resize", "1_" + img.FileName);
var crop1 = img.Crop(300, 300, CropAnchorPosition.Center).Save(
                     "crop", "1_" + img.FileName);
var rotate1 = img.Rotate(45, Color.White).Save("rotate", "1_" + img.FileName);
var scale1 = img.Scale(90).Save("scale", "1_" + img.FileName);

The next section sets the ImageUrl for the image controls. Since each command in the above code block ends with a call to the Save method, each resulting object contains a PathInfo object for each image. Using the OriginalPath property will return the complete path to the saved image. This is an important note: most of the methods available on WebImage or GenericImage are Fluent, the Save method is not.

C#
img1.ImageUrl = resize1.OriginalPath;
img2.ImageUrl = crop1.OriginalPath;
img3.ImageUrl = rotate1.OriginalPath;
img4.ImageUrl = scale1.OriginalPath;

Example 2: Single image, chained manipulation

What if you want to do more than one manipulation on one image? Simple, just call each method in the order that you want the manipulation to take place:

C#
var combo1 = img.Resize(400, 250)
            .Crop(200, 200, CropAnchorPosition.Center)
            .Save("combo", "1_" + img.FileName);
var combo2 = img.Rotate(45, null)
            .Crop(200, 200, CropAnchorPosition.Center)
            .Rotate(90, null)
            .Crop(100, 100, CropAnchorPosition.Center)
            .Save("combo", "2_" + img.FileName);

There's not much more to explain for this example. Because of the Fluent interface, the chaining of the methods makes it readable and easy to understand.

Image 6

Combined manipulation result from the included sample project

It's also possible to combine multiple manipulations with one line of code:

C#
img.ProcessAndSave(new ImageInfo {MaxResizeWidth = 300, RotateAngle = 90});

In the above example, the ProcessAndSave method takes the ImageInfo object as a parameter. This example uses an object initializer to set the maximum resize width and the rotation angle.

Example 3: Single image, multiple manipulations

The example above can be taken further by providing a list of ImageInfo objects to the ProcessAndSaveMultiple method. The example below will generate four separate images, each manipulated in the way defined in the ImageInfo objects.

C#
var gallerySize = new ImageInfo {Path = "gallery", MaxResizeWidth = 600};
var featureSize = new ImageInfo {Path = "feature", MaxResizeHeight = 150};
var thumbnailSize = new ImageInfo {Path = "thumb", 
                    MaxResizeWidth = 100, MaxResizeHeight = 100};
var squareSmall = new ImageInfo
            {
              Path = "square",
              MaxResizeWidth = 75,
              MaxResizeHeight = 75,
              CropWidth = 50,
              CropHeight = 50
            };
img.ProcessAndSaveMultiple(new List<imageinfo> 
            {
                gallerySize, 
                featureSize, 
                thumbnailSize, 
                squareSmall
            });

Example 4: Extract and optimize images in a Zip file

Also included in this library is a utility to extract images from a zip file. To extract the images from a zip file, simply provide the ZipImage constructor with the Stream from the file itself:

C#
var zip = new ZipImage(fileUploader.PostedFile.InputStream);

//save multiple versions of each using the same ImageInfo objects in Example 3
zip.SaveAllMultiple(new List<imageinfo> {gallerySize, featureSize, 
                                            thumbnailSize, squareSmall});

In the first line of the example above, we just provided the ZipImage constructor with the path to the Zip file. This will load the zip file and extract all of the images from the zip file.

**Note: This functionality requires the SharpZip library.

C#
var zip = new ZipImage(fileUploader.PostedFile.FileName);

The second line uses the technique shown in Example 3 to create and save multiple manipulated images for every image extracted from the zip file.

C#
zip.SaveAllMultiple(new List<imageinfo> {gallerySize, 
                    featureSize, thumbnailSize, squareSmall});

Other features

That's the basics of using the LeftImage library, but there are some other features to be aware of. You may be asking, if you use the techniques shown in examples 3 and 4 to upload and manipulate images, how do you get access to each of the images that were created? Simple, use the SavedImages property to get a list of images that have been saved. This can be particularly useful if you encounter an error within a transactional procedure:

C#
//load and save images in zip file
try
{
    var zip = new ZipImage(fileUploader.PostedFile.FileName);
    zip.SaveAll();

    //loop through saved images, and create database record for each
    foreach (var image in zip.SavedImages)
    {
        //create 
        var p = new Photo();
        p.GalleryID = 11;        //For illustration purposes only
        p.PathToImage = string.Concat(image.Path, "/", image.FileName);
        p.Save();
    }
}
catch (Exception ex)
{
    //error occurred during save, so delete any images that were saved
    WebImage.Delete(zip.SavedImages);
}

The LeftImage library also provides more shortcuts through the use of Extension Methods:

C#
using LeftImage.Extensions;

//is the uploaded image actually an image?
var isSupported = fileUploader.IsSupportedFormat();

//process and save the images straight from the FileUpload variable
fileUploader.Process(new ImageInfo {Path = "pix", MaxResizeWidth = 300}).Save();

//do the same using the ProcessAndSave method
fileUploader.ProcessAndSave(new ImageInfo {Path = "pix", MaxResizeWidth = 300});

//call one manipulation from the FileUpload variable
fileUploader.Resize(100, null).Save();

//or chain them together
fileUploader.Resize(100, null).Crop(50, 50, CropAnchorPosition.Center).Save();

Conclusion

That was a quick look at the library. I hope you find it useful. I hope to update this with more features in the future (Opacity, Watermarking, Text Overlay, etc.), and will post those here when I do.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)