Skip to content

Getting Started

Five concrete scenarios, each ~3 minutes.


Terminal window
dotnet add package Pragmatic.Imaging

The NuGet includes the native binary for win-x64. Linux and macOS need a locally-built binary today — see native-deployment.md.


Load a JPEG, thumbnail it, write WebP.

using Pragmatic.Imaging;
using var pipe = ImagePipeline.Load(File.ReadAllBytes("photo.jpg"));
pipe.Thumbnail(maxWidth: 400, maxHeight: 400);
using var output = File.Create("photo-thumb.webp");
pipe.EncodeTo(output, ImageFormat.WebP);

Thumbnail preserves aspect ratio and fits the longest side within the box. For an exact fixed size, use Resize(width, height).


Grayscale + sharpen + tonal tweaks.

using var pipe = ImagePipeline.Load(bytes);
pipe.Grayscale()
.Sharpen(sigma: 1.5f, threshold: 2)
.Brightness(10) // -255..255
.Contrast(15f); // additive; 0 = identity
using var output = File.Create("scan.png");
pipe.EncodeTo(output, ImageFormat.Png);

See operations.md for every filter parameter.


Scenario 3 — inspect an upload before decoding

Section titled “Scenario 3 — inspect an upload before decoding”

Validate dimensions and format cheaply (header only) before running anything expensive, then hand the same limits to Load.

using Pragmatic.Imaging;
var info = ImageInfo.FromStream(Request.Body, maxBytes: 65_536);
if (info.Format is not (ImageFormat.Jpeg or ImageFormat.Png or ImageFormat.Webp))
return BadRequest("Unsupported format");
if (info.Width > 8000 || info.Height > 8000)
return BadRequest("Image too large");
Request.Body.Position = 0; // ImageInfo only read the header
var options = new ImagingOptions
{
MaxWidth = 8000,
MaxHeight = 8000,
MaxMegapixels = 50,
AllowedFormats = [ImageFormat.Jpeg, ImageFormat.Png, ImageFormat.Webp],
};
using var pipe = ImagePipeline.Load(Request.Body, options);
// ... proceed with processing

ImagePipeline.Load re-checks the same ImagingOptions from the header before decoding, so even if you skip the manual pre-check the limits still hold. AllowedFormats is a fail-closed allow-list; a rejected upload throws ImagingException { Reason = FormatNotAllowed }.


ImageBatch is static and works on byte[] inputs with bounded concurrency.

using Pragmatic.Imaging;
var files = Directory.GetFiles("photos", "*.jpg");
var images = await Task.WhenAll(files.Select(f => File.ReadAllBytesAsync(f)));
byte[][] thumbs = await ImageBatch.ThumbnailsAsync(
images,
maxWidth: 256, maxHeight: 256,
format: ImageFormat.WebP,
quality: 75,
maxConcurrency: 4); // 0 → Environment.ProcessorCount / 2
for (var i = 0; i < files.Length; i++)
await File.WriteAllBytesAsync(Path.ChangeExtension(files[i], ".thumb.webp"), thumbs[i]);

maxConcurrency caps how many pipelines are alive at once — 4–8 is a safe start on a typical server. For a custom per-item operation, use ImageBatch.ProcessAsync(images, data => …).


No pipeline needed — QR generation is a direct static call.

using var output = File.Create("qr.png");
QrCode.GeneratePng(
text: "https://pragmaticdesign.net",
output: output,
moduleSize: 10, // pixels per module (1–1000)
margin: 2); // quiet zone in modules (≤100)

Output is always PNG, black on white. Thread-safe, no options object.


When you don’t need a pipeline, ImageConverter wraps the common cases:

byte[] thumb = await ImageConverter.ThumbnailAsync(bytes, 400, 400, ImageFormat.Jpeg, quality: 90);
byte[] webp = await ImageConverter.ConvertAsync(bytes, ImageFormat.WebP);
byte[] clean = ImageConverter.StripExif(bytes); // drop metadata via re-encode
[HttpGet("/thumbnail")]
public async Task ThumbnailAsync(CancellationToken ct)
{
var bytes = await GetImageAsync(ct);
using var pipe = ImagePipeline.Load(bytes, ImagingOptions.Strict);
pipe.Thumbnail(400, 400);
Response.ContentType = "image/webp";
await pipe.EncodeToStreamAsync(Response.Body, ImageFormat.WebP, ct: ct);
}

Always pass ImagingOptions (start from ImagingOptions.Strict) for untrusted input — the defaults are conservative but not tailored to your workload.


  • Pragmatic.Imaging.Samples — QR / image info / resize / format / filters / crop / rotate / flip / chained transforms / batch