Trim scans pixels to remove a uniform border without a known crop rectangle.
dotnet add package RecursiveAI.OneImageRequires .NET 10 (net10.0); .NET 9 and earlier aren’t supported.
using OneImage; // input.png is in the zip. Image.Load("input.png") .Trim().Save("trimmed.png"); Console.WriteLine("Wrote trimmed.png");
Wrote trimmed.pngUnzip the example, then dotnet run.
The full program
The example creates a 200 × 140 white image with a blue rectangle, a red stripe, and a 20-pixel border. The pixel construction below defines the complete input, so you can also run it without a sample file.
using OneImage; // Blue rectangle with a red stripe on white. const int width = 200, height = 140; var pixels = new Rgba32[width * height]; var white = new Rgba32(255, 255, 255, 255); var blue = new Rgba32(20, 100, 220, 255); var red = new Rgba32(220, 40, 30, 255); for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) { bool inside = x >= 20 && x < 180 && y >= 20 && y < 120; bool stripe = x >= 90 && x < 110; pixels[y * width + x] = inside ? (stripe ? red : blue) : white; } Image.FromPixels<Rgba32>(pixels, width, height) .Save("input.png"); Image input = Image.Load("input.png"); Image trimmed = input.Trim(); trimmed.Save("trimmed.png"); Console.WriteLine( $"Before: {input.Width}x{input.Height}"); Console.WriteLine( $"After: {trimmed.Width}x{trimmed.Height}");
dotnet run prints:
Before: 200x140 After: 160x100
Trim scans pixels immediately, then returns a cropped image. A threshold outside 0–255 throws ArgumentOutOfRangeException; CMYK and Lab formats throw ImageOperationException.
For CMYK or Lab inputs, convert to sRGB with image.ConvertColor(ColorProfile.Srgb) before calling Trim.
Variations
Specify white and require an exact match. Use a zero threshold when only the exact background color should be removed:
using OneImage; Image trimmed = Image.Load("input.png").Trim( threshold: 0, background: new Rgba32(255, 255, 255, 255)); trimmed.Save("exact.png"); Console.WriteLine($"exact.png: {trimmed.Width}x{trimmed.Height}");
exact.png: 160x100Related recipes
The short answer
Use Image.Load("input.png").Trim() and save the returned image. OneImage uses each frame’s top-left pixel as its background unless you supply a color. It returns the smallest rectangle containing pixels that don’t match that background, with a default per-channel tolerance of 10 on a 0–255 scale.
How do I remove the border from an image?
For a uniform margin around a product image, screenshot, or scanned graphic, Trim finds the content bounds from the pixels. The example above starts with a 200 × 140 image and removes a 20-pixel white margin on all sides, leaving 160 × 100 pixels. Those dimensions come from the generated sample, not a fixed crop built into Trim.
Use the default background detection when the top-left pixel represents the surrounding margin. Supply background: when you already know the intended border color or when that corner contains something else. The exact-white variation shows both the color and the tolerance explicitly.
The border must be distinguishable by color. This is not an object detector: a patterned frame or a dark outline attached to the subject is not automatically recognized as unwanted decoration. A single nonbackground speck near an edge can also keep that edge in the resulting rectangle.
How do I remove a white border without cutting off content?
Choose the tolerance to match the input. A threshold of zero accepts only an exact channel match. The default of 10 allows small differences from the chosen background. Increasing it treats more pixels as background, including potentially pale content that you wanted to keep. Inspect the result before replacing the original file.
The source defines matching on 8-bit RGBA, including alpha. Fully transparent pixels match one another even if their hidden RGB values differ. This makes a transparent margin a useful input as well as a solid white margin.
If every pixel matches the background, Trim returns the single top-left pixel, not an empty image. For animation, it takes the union of the content bounds across frames so the frames stay aligned. A moving object therefore does not get a different crop rectangle on every frame.
How is trimming different from cropping an image in C#?
Cropping uses coordinates you already know. Trimming discovers those coordinates from a background comparison. Use Crop(x, y, width, height) when the desired rectangle is fixed or chosen by a user. Use Trim when the margin varies between inputs but has a consistent color within each input.
Most OneImage geometry operations are lazy. Trim is different because discovering the rectangle requires reading the pixels immediately. The scan runs in bands of rows; the returned crop is lazy and can decode the source again when saved. Don’t assume that calling Trim is only a metadata operation or that no input has been read until Save.
The returned image is a rectangle. It does not erase white areas inside the subject, fill holes, replace the background, or create a cutout following a curved outline. Save to a different path so you can compare the original and trimmed bounds.