Webority.Imaging 0.7.2

dotnet add package Webority.Imaging --version 0.7.2
                    
NuGet\Install-Package Webority.Imaging -Version 0.7.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Webority.Imaging" Version="0.7.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Webority.Imaging" Version="0.7.2" />
                    
Directory.Packages.props
<PackageReference Include="Webority.Imaging" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Webority.Imaging --version 0.7.2
                    
#r "nuget: Webority.Imaging, 0.7.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Webority.Imaging@0.7.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Webority.Imaging&version=0.7.2
                    
Install as a Cake Addin
#tool nuget:?package=Webority.Imaging&version=0.7.2
                    
Install as a Cake Tool

Webority.Imaging

Image decoding, encoding and processing for .NET. Load an image from a file, stream or byte buffer, resize, crop, rotate and colour-manage it, and save it in another format. Written in managed code, with no native dependencies. Targets .NET 10 and .NET 9.

using Webority.Imaging;
using Webority.Imaging.Processing;

using Image image = Image.Load("photo.jpg");
image.Mutate(x => x.Resize(new Size(800, 600)));
image.Save("photo.webp");

Fill(Color, RectangleF) paints a box over every frame, for redaction or masks: it covers each pixel whose centre lies inside the box, with no antialiasing, and clips to the image. Fill(Color, IEnumerable<RectangleF>) paints many boxes in one pass, and each takes optional GraphicsOptions (Opacity blends the colour over the pixels).

Resize(Size, ResizeOptions?) fits the image inside the box and keeps its aspect ratio. In the default Fit mode it never enlarges an image unless ResizeOptions.Upscale is set. ResizeMode.Cover, Pad and Stretch return exactly the box, and Resize(width, height, mode) makes you choose the mode. Save(string) picks the encoder from the file extension; Save(Stream) without an encoder keeps the format the image was loaded in. Pass an encoder object to choose settings, and cap decode memory with an immutable ImagingConfiguration that you build once and share:

using Webority.Imaging;
using Webority.Imaging.Formats;
using Webority.Imaging.Formats.Webp;
using Webority.Imaging.Processing;

DecoderOptions decoderOptions = new()
{
    Configuration = new ImagingConfiguration { Memory = new MemoryOptions { AllocationLimitMegabytes = 256 } },
    MaxFrames = 1,
};

using Image image = await Image.LoadAsync(input, decoderOptions, cancellationToken);
image.Mutate(x => x
    .AutoOrient()
    .Resize(new Size(1500, 1500), new ResizeOptions { Mode = ResizeMode.Fit }));
await image.SaveAsync(output, new WebpEncoder { Quality = 80, Metadata = MetadataPolicy.Strip }, cancellationToken);

Image.Load, Image.Load<TPixel> and Image.Identify take a stream, a file path, a byte[], a ReadOnlyMemory<byte> or (synchronously) a byte span, with an optional DecoderOptions last; Image.TryIdentify checks bytes without throwing. The library never disposes a stream you pass in and reads from its current position. Async methods make the stream I/O asynchronous; decoding and encoding run on the calling thread.

image.ToBytes() and image.Save(IBufferWriter<byte>) write an encoded image without a stream. Encoders keep the ICC colour profile by default and drop EXIF, XMP and IPTC; set Metadata to MetadataPolicy.Strip or MetadataPolicy.Keep to change that.

Safety limits

Image.Load and Image.Identify read the header first and refuse an image over 100 megapixels or 1,000 frames with an ImageLimitExceededException, before any pixels are allocated. Change this with DecoderOptions.Limits, a DecodeLimits that also has MaxInputBytes. Every failure caused by the input derives from ImageException.

Optimize an upload

Image.OptimizeAsync turns an uploaded photo upright, resizes it and re-encodes it in one call. The default Mode = ResizeMode.Fit shrinks it to fit MaxSize and never enlarges it; Cover, Pad and Stretch return exactly MaxSize for fixed avatars and thumbnails. A JPEG stays a JPEG and anything else becomes a PNG, which keeps transparency; set Format to choose JPEG, PNG or WebP. Metadata defaults to KeepColorProfile, which drops EXIF (camera and location data), XMP and IPTC; Strip also drops the ICC profile after converting to sRGB. Background (white by default) fills a Pad border and flattens transparency for JPEG. The source can be a stream, a byte[], ReadOnlyMemory<byte> or a file path. OptimizeManyAsync decodes once and writes a ladder of sizes, such as thumbnails.

using Webority.Imaging;
using Webority.Imaging.Formats.Jpeg;
using Webority.Imaging.Formats.Png;

var options = new OptimizeOptions
{
    MaxSize = new Size(1600, 1600),
    AcceptedFormats = [JpegFormat.Instance, PngFormat.Instance],
};

OptimizedImage optimized = await Image.OptimizeAsync(upload, options, cancellationToken);
await blob.UploadAsync(optimized.OpenRead(), optimized.ContentType, cancellationToken);

A server that runs several uploads at once sets Configuration once, on options it shares, to apply the thread budget and hosting recommendations below:

static readonly OptimizeOptions Options = new()
{
    MaxSize = new Size(1600, 1600),
    Configuration = new ImagingConfiguration
    {
        MaxDegreeOfParallelism = 1,
        Memory = new MemoryOptions { MaximumPoolSizeMegabytes = 64 },
    },
};

Catch ImageException to refuse any bad upload: a file that is not an image, or a format outside AcceptedFormats, throws UnknownImageFormatException; damaged content throws InvalidImageException; and an image past Limits throws ImageLimitExceededException.

Thread budget

ImagingConfiguration.MaxDegreeOfParallelism defaults to all cores. A single job gains about 15% from the extra cores. A server that runs several uploads at once can set it to 1: on a 16-core machine, 8 concurrent jobs lost under 5% throughput, and each request stays on one thread.

Hosting recommendations

Measured with the --concurrency benchmark (orient, resize to 1500 px, WebP q78, three 12 to 24 MP JPEGs) on a 16-core, 64 GB Linux host, median of three runs per setting, 8 concurrent jobs:

Setting Images per second Memory held after the run
Runtime defaults (workstation GC, tiered PGO on, default pool) 20.3 (noisy, 18 to 24 across repeats) about 1.4 GB
DOTNET_gcServer=1 (PGO on) 22.3 about 1.3 GB
DOTNET_TieredPGO=0 23.3 about 1.3 GB
MaximumPoolSizeMegabytes = 64 22.0 about 0.85 GB
MaximumPoolSizeMegabytes = 256 22.7 about 1.2 GB
  • Leave server GC off. It did not raise throughput at 1, 4 or 8 jobs and held up to 10% more memory at 1 and 4 jobs. Its 22.3 images per second above is a PGO-on run, so it is a gain only against a PGO-on baseline.
  • DOTNET_TieredPGO=0 looked 8 to 13% faster on the 16-core host, but repeats with the core count limited to 2 and 8 (DOTNET_PROCESSOR_COUNT) showed no consistent winner, with run-to-run swings of 10 to 20% on a shared machine. Keep the runtime default.
  • Limiting the host to 2 and to 8 cores gave the same picture: no GC or PGO setting won consistently, and a 64 MB pool kept about 40% less memory (about 0.6 GB against 1.06 GB on 2 cores) at equal throughput within noise.
  • The default pool is a fixed fraction of the memory the process may use, so it grows with the host. A host that runs several services, or a container with a tight limit, should set new ImagingConfiguration { Memory = new MemoryOptions { MaximumPoolSizeMegabytes = 64 } }: it cut retained memory by about a third at 8 jobs for a 3 to 6% throughput cost.
  • Task size for parallel row work is fixed at 4096 pixels; sweeping 1024 to 65536 on 2 MP and 20 MP images at 1, 4 and 8 jobs changed no stage by more than 4%.

Formats

  • JPEG
  • PNG
  • WebP
  • GIF
  • BMP
  • TIFF

Proprietary. For use within Webority Technologies products.

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on Webority.Imaging:

Package Downloads
Webority.Social

Social media posting and social analytics a product runs on its own database: a publication queue and runner for LinkedIn, X, Facebook, Instagram, Threads, Bluesky, YouTube, Reddit and Google Business Profile, daily post, account and audience statistics, the run log and the tables. The product owns its posts, approvals, schedule and credentials.

Webority.Pdf

Webority's PDF library: generate documents, and open, inspect, unlock, protect, merge, split, stamp, render, read, sign, redact and optimise existing files.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.7.2 2,093 11/2/2026
0.7.1 1,351 10/28/2026
0.7.0 102 10/28/2026
0.6.0 96 10/26/2026
0.5.0 124 10/16/2026
0.4.2 135 10/15/2026
0.4.1 96 10/14/2026
0.4.0 128 10/12/2026
0.3.0 126 10/10/2026
0.2.0 126 10/9/2026
0.1.0 131 10/9/2026