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 .