oneimage

Resize an image in C#

Resize images in C# on any OS with pure .NET code: keep the aspect ratio, fit or crop to a box, make thumbnails, set JPEG quality and resize ASP.NET Core uploads.

To resize an image in C#, load it, call Resize with the width you want and save it. With OneImage that’s one line, Image.Load("photo.jpg").Resize(width: 800).Save("photo-800.jpg"), and the height follows the aspect ratio. It is pure C#, so the same code runs on Windows, Linux, macOS and in containers, unlike System.Drawing, which is Windows-only on current .NET. Below: fitting and cropping to a box, thumbnails, not enlarging small images, quality settings, several sizes at once and ASP.NET Core uploads. Every sample was run against OneImage 1.6.0 on .NET 10.

TerminalNuGet
dotnet add package RecursiveAI.OneImage

OneImage targets .NET 10. The examples use a 3000×3002 photograph (photo.jpg) and a phone-style photo stored as 1200×800 with an EXIF orientation of 6, meaning “rotate 90° to display”, and a GPS position (portrait.jpg).

Resize to a width and keep the aspect ratio

Program.cs.NET 10
using OneImage;

// 800 px wide; the height follows the aspect ratio.
Image.Load("photo.jpg").Resize(width: 800).Save("photo-800.jpg");

The 3000×3002 photo becomes 800×801. Give only height: to fix the height instead. The output format comes from the extension, so .png, .webp, .gif, .tif, .bmp or .ico work the same way. Nothing is decoded until Save, and for JPEG input the decoder reads the image at 1/2, 1/4 or 1/8 scale when that is enough for the target size, so a large photo isn’t held in memory at full resolution.

Resize to a fixed size: fit, crop or pad

Give both a width and a height and choose how the image fills that box with fit:

Program.cs.NET 10
using OneImage;

Image photo = Image.Load("photo.jpg");

// Fit inside 800x600 (Fit.Contain is the default): 600x600 for a square photo.
photo.Resize(width: 800, height: 600).Save("contain.jpg");

// Fill 800x600 exactly and crop what overflows, keeping the center.
photo.Resize(width: 800, height: 600, fit: Fit.Cover).Save("cover.jpg");

// Fit inside 800x600 and pad the rest with white.
photo.Resize(width: 800, height: 600, fit: Fit.Pad, background: new Rgba32(255, 255, 255, 255))
     .Save("pad.jpg");

These wrote 600×600, 800×600 and 800×600 files. Image is immutable, so one loaded photo can feed all three.

FitResult
Contain (default)Fits inside the box; aspect ratio kept; one side may be smaller.
CoverFills the box; aspect ratio kept; the overflow is cropped. Choose the kept part with anchor: (nine positions, or Anchor.Smart, which picks the busiest area).
PadFits inside the box, then pads to the exact size with background:.
BoxPadLike Pad, but never enlarges.
MinCovers the box without cropping; never enlarges.
StretchExactly the box; aspect ratio not kept.

Create a thumbnail in C#

For images that go on the web, use Image.Thumbnail. It is Resize with the defaults a published copy needs:

Program.cs.NET 10
using OneImage;

// Upright, at most 400 px wide, never enlarged, sRGB, EXIF and GPS removed.
Image.Thumbnail("portrait.jpg", 400).Save("portrait-400.jpg");

// A 200x200 square that fills the box, for avatars and grids.
Image.Thumbnail("portrait.jpg", 200, 200, fit: Fit.Cover).Save("portrait-square.jpg");

In order, it applies the EXIF orientation, resizes (never larger than the original unless you pass upscale: true), converts to sRGB with a compact embedded profile and removes EXIF, XMP and IPTC. The portrait stored sideways at 1200×800 came out upright at 400×600, and the square at 200×200, both with no EXIF block, so no GPS position. Phone photos are the usual source of “my resized image is rotated”: the pixels are stored sideways and the orientation tag says how to show them (see EXIF orientation in C#). OneImage applies that tag when it loads, in Load as well as in Thumbnail.

Don’t enlarge small images

Resize gives you the size you asked for, even if that means enlarging. Pass upscale: false when the target is a maximum:

Program.cs.NET 10
using OneImage;

// Resize enlarges when asked to; upscale: false stops at the original size.
// portrait.jpg is 800x1200 once upright, so this writes 800x1200, not 2000x3000.
Image.Load("portrait.jpg").Resize(width: 2000, upscale: false).Save("not-enlarged.jpg");

A plain Load and Save keeps the metadata, so this file still carries the GPS block. That’s right for archiving. For anything public, use Thumbnail or call StripMetadata() before saving.

Resize without losing quality

Two settings decide how a resized image looks: the resampling filter and the encoder quality.

Program.cs.NET 10
using OneImage;

var jpeg = new SaveOptions { EncoderOptions = new JpegEncoderOptions { Quality = 85 } };

Image.Load("photo.jpg")
     .Resize(width: 1200, filter: ResamplingFilter.Lanczos3)
     .Save("photo-1200.jpg", jpeg);

Make several sizes from one image

Responsive images need the same picture at several widths. Load once and derive each size:

Program.cs.NET 10
using OneImage;

Image photo = Image.Load("photo.jpg");   // nothing is decoded yet

foreach (int width in new[] { 320, 640, 1280 })
{
    photo.Resize(width: width, upscale: false).Save($"photo-{width}.webp");
}

This wrote 320×320, 640×640 and 1280×1281 WebP files of 34, 72 and 166 KB, ready for a srcset.

Resize uploaded images in ASP.NET Core

The same calls take a Stream. This minimal API endpoint stores every upload as an upright JPEG at most 1600 px wide, with private metadata removed:

Program.csASP.NET Core · .NET 10
using OneImage;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

string folder = Path.Combine(app.Environment.ContentRootPath, "uploads");
Directory.CreateDirectory(folder);

app.MapPost("/photos", async (IFormFile file) =>
{
    try
    {
        await using Stream upload = file.OpenReadStream();
        Image photo = Image.Thumbnail(upload, 1600);   // upright, at most 1600 px wide, no EXIF/GPS

        string name = $"{Guid.NewGuid():N}.jpg";
        await photo.SaveAsync(Path.Combine(folder, name));
        return Results.Ok(new { name, photo.Width, photo.Height });
    }
    catch (ImageException ex) // not an image, damaged, or over the size limits
    {
        return Results.BadRequest(ex.Message);
    }
}).DisableAntiforgery();

app.Run();

Posting the two test photos returned {"width":1600,"height":1601} and {"width":800,"height":1200}. The portrait was turned upright and not enlarged, and neither stored file had an EXIF block. A text file got a 400 with “The data is not in a recognized image format.” Uploads are untrusted, so OneImage’s size limits are on by default and are checked from the file headers before large buffers are allocated (limits).

If you’d rather resize on request than on upload, with URLs like /photos/a.jpg?width=400, the OneImage.Web middleware does that with a disk cache.

What about System.Drawing, SkiaSharp and ImageSharp?

OneImage’s published benchmarks include JPEG and WebP thumbnail tasks against ImageSharp, SkiaSharp, NetVips and Magick.NET, with memory use, the losses and the method. For everything else it does, see the overview.