Browser-side image processing for Blazor. Load, transform, annotate and export images entirely on the user's device, from strongly typed C#.
No server round trips. No base64. No JavaScript image library.
var result = await processor.ProcessAsync(
uploadedFile,
ImagePipeline.Create()
.AutoOrient()
.Cover(512, 512)
.Sharpen(0.3f),
new ImageExportOptions
{
Format = ImageFormat.WebP,
Quality = 0.82,
Metadata = MetadataPolicy.StripSensitive,
MaxFileSize = 120 * 1024,
});That runs in the browser. The original file never leaves it, the phone's rotation is applied, the GPS coordinates are stripped, and the result is a WebP that fits the size budget you asked for.
Targets .NET 8, 9, and 10 · Everything works on Blazor WebAssembly and Interactive Auto once interactive. Interactive Server works too: PNG, JPEG, BMP and GIF are coded on the server, while WebP, AVIF and editor previews cross the circuit. So does Blazor Hybrid (MAUI, WPF, Windows Forms), the same way but inside the app. Prerendering, ASP.NET Core and console hosts get the headless API with the managed codecs.
Bmage's documentation website lives in Demo - run the
Demo/Server project, or visit bmage.bitplatform.dev.
- Why Bmage
- Packages
- Installation
- The simple path
- The full editor
- What is in the box
- Performance
- Where it runs
- MCP server (for AI agents)
- Tests
- Documentation
- License
Blazor developers who need to crop an avatar or shrink an upload have had two options: send the full-resolution file to a server, or assemble several JavaScript libraries behind hand-written interop. Bmage is a third option: one coherent, Blazor-native image processing platform where the engine itself is C#.
- Non-destructive by construction. An edit is a list of operations, not a mutated buffer. Undo costs a few hundred bytes, previews are cheap, and any earlier step can be changed without redoing the rest.
- The engine is this project. The resampler, rasteriser, colour pipeline, TrueType text engine, and the PNG, JPEG, BMP and GIF codecs are implemented here. The browser is used only for what only it can do: WebP and AVIF.
- Large images stay usable. Interactive editing runs on a proxy sized for the display and replays at full resolution on export, so a 24 megapixel photo does not stall the interface.
- Privacy is the default. Metadata is removed unless you ask for it. Location data cannot leak into an exported avatar by accident.
- Nothing about the browser is assumed. Format support is probed by actually encoding a pixel. When a browser substitutes PNG for the AVIF you requested, you get an exception, not a silent surprise.
- Headless first. Every capability works without the editor component, so the same pipeline runs in an upload handler or a console tool.
- Selective edits and layers. Any edit can be applied through a mask: a gradient, a radial spotlight, a tone or colour range, brush strokes, a segmentation model's matte. Image, fill and adjustment layers composite with the W3C blend modes.
- Edits are data. A document, pipeline, layers, masks and annotations included, writes to JSON and reads back as the same edit, so the browser can send the edit instead of the pixels and a server can replay it at full resolution.
- Every core, when you want it. Set
MaxDegreeOfParallelismand operations spread their rows over that many cores with identical pixels; one thread by default, which suits a busy server. In the browser decoding and encoding run in Web Workers, off the page's thread. - Memory you can predict. A pipeline estimates its peak before it runs, a budgeted allocator enforces a ceiling, and a batch streams its files and results so it holds only the images in flight.
| Package | What it contains | Depends on |
|---|---|---|
Bit.Bmage |
The engine, browser codecs, capabilities, loading and export, headless processing on a server, and the BmageEditor / BmageDropZone components |
Microsoft.AspNetCore.Components.Web |
Everything ships in the one package. The editor's stylesheet is opt-in, so an app that brings its own UI or only processes images headlessly never loads it.
dotnet add package Bit.BmageRegister the services in Program.cs:
using Bit.Bmage;
builder.Services.AddBitBmageServices();For server-side or console use, without any browser integration, register AddBitBmageHeadlessServices() instead.
A WebAssembly app whose only use of Bmage is BmageEditor can skip the registration and lazy load Bit.Bmage.wasm
instead; see lazy loading.
Add the stylesheet if you use the editor:
<link rel="stylesheet" href="_content/Bit.Bmage/bit-bmage-editor.css" />In the browser, consider AOT compilation in the project that runs on WebAssembly. Bmage is tuned for the default interpreter, where the editor opens a 12 megapixel photo in about 50 ms, but work that stays in .NET still runs 4 to 12× faster compiled ahead of time:
<RunAOTCompilation>true</RunAOTCompilation>@inject ImageLoader Loader
@inject ImageExporter Exporter
<InputFile OnChange="OnChange" accept="image/*" />
@code {
async Task OnChange(InputFileChangeEventArgs e)
{
using var image = await Loader.LoadAsync(e.File);
using var thumb = await ImagePipeline.Create()
.AutoOrient()
.MaxSize(400, 400)
.ExecuteAsync(image);
await Exporter.DownloadAsync(thumb, "thumbnail",
new ImageExportOptions { Format = ImageFormat.WebP, Quality = 0.85 });
}
}@using Bit.Bmage.Editor.Components
<BmageEditor @ref="editor" />
<button @onclick="() => editor.DownloadAsync("edited")">Save</button>Crop, rotate, straighten, resize, canvas size, trim, adjustments with a histogram, a colour mixer, filters, painting with a brush and an eraser, fill, magic eraser, eyedropper, rectangle, ellipse, lasso and magic wand selections, annotations, redaction, layers, before and after comparison, history, project files and export, in one component. It is themeable through CSS custom properties, fully localisable, keyboard accessible, touch friendly and right-to-left aware. Every part of its UI can be replaced while keeping the engine:
<BmageEditor Strings="german" Direction="rtl" Class="bmg-theme-dark">
<Toolbar Context="editor">
<button @onclick="() => editor.SetTool(EditorToolKind.Crop)">Crop</button>
<button disabled="@(!editor.CanUndo)" @onclick="editor.Undo">Undo</button>
</Toolbar>
</BmageEditor>| Area | What you get |
|---|---|
| Loading | IBrowserFile, byte arrays, streams, data URLs, object URLs, remote URLs, clipboard, drag and drop, camera |
| Decoding | PNG, JPEG, BMP and GIF in managed code; PNG, JPEG, WebP, AVIF and GIF through the browser |
| Encoding | PNG, JPEG and BMP in managed code; PNG, JPEG, WebP and AVIF through the browser |
| Transforms | Crop, aspect crop, resize in six modes, rotate, flip, straighten, canvas size and margins, trim to content, skew, affine and perspective warps; annotations and layers stay on the content they mark |
| Adjustments | Brightness, contrast, saturation, hue, exposure, gamma, levels, temperature, tint, vibrance, shadows, highlights, whites, blacks, white balance (picked or automatic), per-colour HSL, channel mixer, colorize, opacity |
| Filters | Grayscale, black and white mixer, sepia, invert, posterize, threshold, gradient map and duotone, blur, motion blur, sharpen, high pass, pixelate, noise, median denoise, vignette, custom convolution and colour matrices |
| Analysis | Histograms, luminance statistics, dominant colour palettes, auto-levels, auto-contrast, saliency-based smart cropping, content bounds for trimming, colour sampling, low-quality placeholders |
| Masks | Rectangles, ellipses, lassos, paths, brush strokes, linear and radial gradients, luminance and colour ranges, magic wand, bitmap mattes, combinations; expand, contract, border, feathering, inversion, relative units; masked edits, alpha cut-outs and plain background removal |
| Layers | Image, fill, adjustment and paint layers (brush with hardness and pen pressure, eraser) with opacity, masks and the W3C blend modes, from Multiply and Screen to Color and Luminosity; pass-through and isolated groups, and clipping to the layer below |
| Drawing | Anti-aliased paths, strokes with caps, joins and dashes, gradients, ellipses, polygons, arrows, freehand, text |
| Text | TrueType fonts shaped with their OpenType tables (ligatures, kerning, marks, contextual alternates), Arabic and Persian joining, right-to-left and mixed text ordered by the Unicode Bidirectional Algorithm, per-character font fallback, wrapping |
| Annotations | Rectangle, ellipse, line, arrow, freehand, polygon, text, highlight, callout, numbered step, image stamp, redaction |
| Metadata | EXIF read and write, GPS, camera data, orientation, ICC profiles, XMP, three privacy policies |
| Pipelines | Composition, optimisation, lazy execution, cancellation, progress, memory estimates, batch processing with streamed inputs and outputs and memory-based admission, and a stopped batch keeping what it finished |
| Editing | Non-destructive documents with layers, undo and redo, memory-aware history, proxy previews, JSON save and restore, self-contained project files that reopen editable |
| Concurrency | Row-parallel operations with identical pixels on any number of threads; browser codecs in a Web Worker pool |
Every number below was measured with BenchmarkDotNet on desktop .NET 10 (see
Tests/Bit.Bmage.Benchmarks). In the browser, with RunAOTCompilation enabled,
WebAssembly lands within about 2.5× of these numbers, and the default interpreter is 4 to 12× slower than that; the WebAssembly
table in performance.md has both. See
docs/performance.md for the full tables and how to reproduce them.
| Operation | Image | Time | Allocated |
|---|---|---|---|
| Thumbnail to 200px | 6000 × 4000 | 23 ms | 23 KB |
| Downscale to 1280px, Lanczos | 3840 × 2160 | 40 ms | 180 KB |
| Upload pipeline: orient, cap at 1920, sharpen | 4000 × 3000 | 101 ms | 238 KB |
| Four adjustments fused into one pass | 3840 × 2160 | 67 ms | 4.6 KB |
| JPEG encode, quality 85 | 3840 × 2160 | 122 ms | 6.7 MB |
| PNG decode | 3840 × 2160 | 88 ms | 37 MB |
Those are on one thread, the default. Given more with MaxDegreeOfParallelism, operations spread their rows over every
core with identical pixels: on a 10 core machine a 24 megapixel downscale runs 4.7× faster, a 4K rotation 6.1×, a
median filter 8.5×. In the browser, decoding and encoding run in Web Workers, off the page's thread.
| Host | Support |
|---|---|
| Blazor WebAssembly | Everything |
| Blazor Web App, Interactive WebAssembly | Everything |
| Blazor Web App, Interactive Auto | Everything once interactive |
| Blazor Web App, Interactive Server | Everything; PNG, JPEG, BMP and GIF are coded on the server, WebP, AVIF and editor previews cross the circuit; see docs/browser-support.md |
| Blazor Hybrid (MAUI, WPF, Windows Forms) | Everything; as Interactive Server, but .NET runs in the app and reaches the WebView without a network; saving a file on Android and iOS is the app's job; see docs/browser-support.md |
| Prerendering | Managed codecs only, and capability detection reports Prerendering; call browser features from OnAfterRenderAsync |
| ASP.NET Core, console, worker | Headless API with the managed codecs, no browser involved |
Samples is the render-mode
harness rather than the docs: one shared Core
project of pages (the capability probe, the managed engine, loading, processing and export, and the editor), hosted
unchanged under Server,
Wasm and
Auto so the same code
runs, prerendered first, in each render mode, and under MAUI,
a Blazor Hybrid app for Android, iOS, macOS and Windows. Each host is also a minimal example of the wiring that
platform needs.
The demo website hosts a Model Context Protocol server at
https://bmage.bitplatform.dev/mcp. Point your coding agent at it to let it search the Bmage API, read worked examples
and setup guides, and review Bmage code. See the MCP server page of the demo website for the full tool list.
cd src/Utilities/Bmage/Tests/Bit.Bmage.Tests && dotnet test # engine tests, no browser needed
cd src/Utilities/Bmage/Tests/Bit.Bmage.Tests.E2E && dotnet test # drives a real browser against the demo website and the samples
cd src/Utilities/Bmage/Tests/Bit.Bmage.Tests.Mcp && dotnet test # the MCP server, hosted in-memory
cd src/Utilities/Bmage/Tests/Bit.Bmage.Tests.Hosting && dotnet test # the samples in every render mode, hosted in-memory
dotnet run --project src/Utilities/Bmage/Tests/Bit.Bmage.Benchmarks -c Release -- --filter "*"- Getting started
- Architecture
- Pipelines
- Layers, masks and blend modes
- The editor component
- Headless processing
- Formats and capabilities
- Metadata and privacy
- Performance
- Threads, workers and memory
- Security
- Browser support
- Extending
- Troubleshooting
MIT. See LICENSE.