Performing image manipulation in C#

Table of contents

SixLabors.ImageSharp

ImageSharp offers a simple and powerful API for common image processing tasks, as well as the ability to extend it with custom operations. It's been crafted from scratch to be highly flexible and extensible. In this article we'll talk about common image manipulations such as resizing and cropping.

Resize image

Here's how we can do a simple resize operation and save the file with the new width and height:

public async Task ResizeImage(string filePath, int height, int width)
{
    // Read the file 
    var fileStream =
        new FileStream(Path.Combine(Directory.GetCurrentDirectory(), filePath),
            FileMode.Open);
    using var image = await Image.LoadAsync(fileStream);

    // Resize the image
    image.Mutate(x => x.Resize(width, height));

    // Generate a new file name for the resized image
    var fileName =
        $"{Path.GetFileNameWithoutExtension(filePath)}_{width}x{height}{Path.GetExtension(filePath)}";
    var newFilePath = Path.Combine("images", fileName);

    // Save the resized image 
    await image.SaveAsync(Path.Combine(Directory.GetCurrentDirectory(), newFilePath));
				
}

Resize image with a given width value

If we only want to use the width to resize the image, we can create a method that calculates the height of the image based on the aspect ratio and only receives the width as argument. The method could look like this:

public async Task ResizeImage(string filePath, int width)
{
    // Read the file 
    var fileStream =
        new FileStream(Path.Combine(Directory.GetCurrentDirectory(), filePath),
            FileMode.Open);
    using var image = await Image.LoadAsync(fileStream);
		
		// Calculate height
    var height = (int) (image.Height * ((float) width / image.Width));

    // Resize the image
    image.Mutate(x => x.Resize(width, height));

    // Generate a new file name for the resized image
    var fileName =
        $"{Path.GetFileNameWithoutExtension(filePath)}_{width}x{height}{Path.GetExtension(filePath)}";
    var newFilePath = Path.Combine("images", fileName);

    // Save the resized image 
    await image.SaveAsync(Path.Combine(Directory.GetCurrentDirectory(), newFilePath));
				
}

Crop Image

We can also do a crop operation using this library. We need to have the information of the part of the image we want to retain, so it's pretty useful to use a Rectangle. The values of the rectangle can be retrieved on the frontend using a library like react-easy-crop. Here's a simple extension method that performs a crop operation:

public static Image Crop(this Image image, CropSettings cropSettings)
{
    image.Mutate(processingContext =>
    {
        processingContext
            .Crop(new Rectangle(
                cropSettings.X,
                cropSettings.Y,
                cropSettings.Width,
                cropSettings.Height));
    });
   
    return image;
}

Crop and resize

We can go further and develop a better combo, crop and resize. For this we need to have the rectangle containing the information that we want to retain and additionally, the width and the height that we want the image to have. For this example we'll be calculating the height to match the post-crop image proportions.

public static Image CropAndResize(this Image image, CropSettings cropSettings)
{
    // Crop and resize the image
    image.Mutate(processingContext =>
    {
        processingContext
            .Crop(new Rectangle(
                cropSettings.X,
                cropSettings.Y,
                cropSettings.Width,
                cropSettings.Height));
    });

    var height = (int) (image.Height * ((float) cropSettings.ResizeWidth / image.Width));

    if (cropSettings.ResizeWidth != default)
    {
        image.Mutate(x => x.Resize(cropSettings.ResizeWidth, height));
    }

    return image;
}

We've added a additional information to our "CropSettings" class: ResizeWidth property that allows us, from the frontend, to define a new width for the image after the crop is done:

public class CropSettings
{
    public int X { get; set; }
    public int Y { get; set; }
    public int Width { get; set; }
    public int Height { get; set; }
    public int ResizeWidth { get; set; }
}

For more information about this library, check the SixLabors.ImageSharp - Github repository .

Author
I’m a passionate full-stack software engineer, architect and Debian lover.