
ImageResize: Resize Images In .NET On The Fly
This is yet another package that was developed to be part of ZauberCMS, but I thought it would be a useful package on it's own. Especially as ImageSharp has a license, albeit very generous before you have to pay, I wanted an OSS alternative for the most common thing I used it for.
ImageSharp?
This is NOT a full replacement for ImageSharp, just for a couple of the resize features. In fact I actually think ImageSharp creates slightly better thumbnails. This package uses SkiaSharp behind the scenes.
You can test it out by just cloning the repo and running the Example project, it has a simple UI example that shows it working, but also allows you to upload your own image to see it being resized in different sizes and qualities.
Repo:
https://github.com/YodasMyDad/ImageResize
As with ImageSharp, it's very easy to use, and once setup, you just pass in the width and/or the height via a querystring on the image and it resizes it on the fly and caches it.
/images/my-image.jpg?width=200
Very easy to get starting with the project, just install the nuget package
dotnet add package ImageResize
and then setup your Program.cs
using ImageResize.Core.Extensions;
var builder = WebApplication.CreateBuilder(args);
// Simple setup with automatic defaults
builder.Services.AddImageResize(builder.Environment);
var app = builder.Build();
app.UseImageResize(); // Before UseStaticFiles and before routing app.UseRouting() etc...
app.UseStaticFiles();
app.Run();
Advanced Configuration
By default, it monitors the img, images and media folder in your wwwroot for images to be resized, but you can update this with whatever folders you like and change a lot of other default settings.
builder.Services.AddImageResize(o =>
{
o.ContentRoots = ["img", "images", "media"]; // URL path prefixes to monitor
o.WebRoot = builder.Environment.WebRootPath; // Where original images are stored (wwwroot)
o.CacheRoot = Path.Combine(builder.Environment.WebRootPath, "_imgcache"); // Where resized images are cached
o.AllowUpscale = false; // Don't enlarge images beyond original size
o.DefaultQuality = 99; // Default JPEG/WebP quality
o.PngCompressionLevel = 6; // PNG compression (0-9)
o.Backend = ImageBackend.SkiaSharp; // Image processing backend (Only one at present)
o.Cache.MaxCacheBytes = 1073741824; // 1GB cache limit (0 = unlimited)
o.Cache.PruneOnStartup = true; // Clean old cache files on app start
});
You can also override in the appSettings.
{
"ImageResize": {
"EnableMiddleware": true, // Enable/disable the middleware
"ContentRoots": ["img", "images", "media"], // URL path prefixes to monitor
"WebRoot": "wwwroot", // Root directory containing original images
"CacheRoot": "wwwroot/_imgcache", // Directory for cached resized images
"AllowUpscale": false, // Prevent enlarging images beyond original size
"DefaultQuality": 99, // Default JPEG/WebP quality (1-100)
"PngCompressionLevel": 6, // PNG compression level (0-9)
"Bounds": {
"MinWidth": 16, "MaxWidth": 4096, // Width limits in pixels
"MinHeight": 16, "MaxHeight": 4096, // Height limits in pixels
"MinQuality": 10, "MaxQuality": 100 // Quality limits (JPEG/WebP only)
},
"HashOriginalContent": false, // Include file content in cache key (slower but more accurate)
"Cache": {
"FolderSharding": 2, // Subfolder levels for cache organization (0-4)
"PruneOnStartup": false, // Clean old cache files when app starts
"MaxCacheBytes": 0 // Cache size limit in bytes (0 = unlimited)
},
"ResponseCache": {
"ClientCacheSeconds": 604800, // Browser cache duration (7 days)
"SendETag": true, // Send ETag headers for caching
"SendLastModified": true // Send Last-Modified headers for caching
},
"AllowedExtensions": [".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".tif", ".tiff"],
"Backend": "SkiaSharp" // Image processing backend
}
}
Wha's more, you can use ImageResize to resize images programatically within your C#. Just get a stream of your image and pas it to the API.
// From a file path
using var fileStream = File.OpenRead("path/to/image.jpg");
// From an HTTP file upload (ASP.NET Core)
public async Task<IActionResult> UploadImage(IFormFile uploadedFile)
{
await using var stream = uploadedFile.OpenReadStream();
// ... process stream
}
// From a byte array
var imageBytes = await File.ReadAllBytesAsync("path/to/image.jpg");
using var memoryStream = new MemoryStream(imageBytes);
// From a URL
using var httpClient = new HttpClient();
using var response = await httpClient.GetAsync("https://example.com/image.jpg");
using var urlStream = await response.Content.ReadAsStreamAsync();
// ...........
// Simple resize with one method call
var options = new ResizeOptions(Width: 1920, Height: 1080, Quality: 90);
using var resizedImage = await resizerService.ResizeAsync(stream, null, options);
// Save the result
await resizedImage.SaveAsync(filePath);
Features
- Querystring-based resizing:
?width=800&height=600&quality=80
- Aspect ratio preservation: Always fits within specified dimensions
- Multiple formats: JPEG, PNG, WebP, GIF (first frame), BMP, TIFF (first page)
- Disk caching: Atomic writes with configurable sharding and size management
- HTTP caching: ETags, Last-Modified, Cache-Control headers
- Concurrency safe: Prevents thundering herd with keyed locks
- Security: Path traversal protection and bounds validation
- Backend support: Extensible codec architecture (SkiaSharp, future backends)
- ImageSharp Compatibility Layer: Drop-in replacement for common ImageSharp operations
- OSS-friendly: MIT licensed with no commercial restrictions