---
title: "Resize uploaded images in ASP.NET Core"
url: https://recursiveai.org/oneimage/cookbook/resize-uploaded-images-aspnet-core/
description: "Resize uploaded images in ASP.NET Core: an endpoint that stores every upload upright, at most 1600 px wide, as WebP without GPS data, and crops a user-picked square. Runnable code with OneImage."
version: "1.10.4"
---

# Resize uploaded images in ASP.NET Core

In a minimal API endpoint, pass the upload’s stream to `Image.Thumbnail` and save the result. That one call turns phone photos upright, shrinks them to a maximum width, converts to sRGB and removes EXIF, so no GPS position is stored. Wrap it in a `try` for `ImageException` to answer 400 when the upload isn’t an image.

```shell
dotnet new web -o Uploads && cd Uploads
dotnet add package RecursiveAI.OneImage --version 1.10.4
curl -L -o earth.jpg \
  https://images-assets.nasa.gov/image/as17-148-22727/as17-148-22727~orig.jpg
repo=https://raw.githubusercontent.com/recurser/exif-orientation-examples
curl -L -o phone.jpg $repo/master/Portrait_6.jpg
```

OneImage needs the .NET 10 SDK. Replace `Program.cs` with:

```csharp
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();
        // Upright, at most 1600 px wide, sRGB, EXIF and GPS removed.
        Image photo = Image.Thumbnail(upload, 1600);

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

app.Run();
```

Start it:

```shell
dotnet run --urls http://localhost:5000
```

and post a photo, a phone photo stored sideways, and a file that isn’t an image, from a second terminal:

```shell
for f in earth.jpg phone.jpg Program.cs
do
  echo "$f: $(curl -s -w ' (%{http_code})' -F "file=@$f" http://localhost:5000/photos)"
done
```

```text
earth.jpg: {"width":1600,"height":1600,"bytes":176776} (200)
phone.jpg: {"width":1200,"height":1800,"bytes":174880} (200)
Program.cs: "The data is not in a recognized image format." (400)
```

The 4579 px photo is stored 1600 px wide as WebP. The phone photo, stored as 1800×1200 with an EXIF orientation of 6, comes out upright and isn’t enlarged. Size limits are on by default and are checked from the file headers before large buffers are allocated, so an oversized upload fails with an `ImageException` too.

## Crop a user-picked square

Avatar pickers send the square the user dragged in the browser with the file. Browsers show photos upright, and so does OneImage, so the coordinates line up. This program has only the avatar endpoint; in your app it sits next to the first one:

```csharp
using OneImage;

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

app.MapPost("/avatar", async (IFormFile file, int x, int y, int size) =>
{
    try
    {
        await using Stream upload = file.OpenReadStream();
        Image photo = Image.Load(upload);   // upright, like the preview the user saw

        // Keep the square inside the image instead of failing on a stray pixel.
        x = Math.Clamp(x, 0, photo.Width - 1);
        y = Math.Clamp(y, 0, photo.Height - 1);
        size = Math.Min(size, Math.Min(photo.Width - x, photo.Height - y));

        Image avatar = photo.Crop(x, y, size, size)
                            .Resize(width: 256, height: 256)
                            .StripMetadata();
        var webp = new MemoryStream();
        await avatar.SaveAsync(webp, WebPFormat.Instance);   // streams name the format
        webp.Position = 0;
        return Results.File(webp, "image/webp");
    }
    catch (ImageException ex)
    {
        return Results.BadRequest(ex.Message);
    }
}).DisableAntiforgery();

app.Run();
```

```shell
dotnet run --urls http://localhost:5000
```

```shell
curl -s -o avatar.webp -w '%{http_code} %{content_type}, %{size_download} bytes\n' \
  -F file=@phone.jpg 'http://localhost:5000/avatar?x=100&y=300&size=800'
```

```text
200 image/webp, 2452 bytes
```

## Limits

- **Uploads are untrusted.** Keep the `try`: damaged data can surface at `SaveAsync`, not only at load. Lower `LoadOptions.Limits` if you accept smaller images than the defaults.
- **ASP.NET Core’s request size limit** (about 28.6 MB by default in Kestrel) applies before OneImage sees the file.

To make many sizes on request instead of one at upload, see [Resize images on the fly](https://recursiveai.org/oneimage/cookbook/resize-images-aspnet-core/). For the options of `Thumbnail`, see [Create a thumbnail](https://recursiveai.org/oneimage/cookbook/create-thumbnail/).
