Webority.Imaging
0.7.2
dotnet add package Webority.Imaging --version 0.7.2
NuGet\Install-Package Webority.Imaging -Version 0.7.2
<PackageReference Include="Webority.Imaging" Version="0.7.2" />
<PackageVersion Include="Webority.Imaging" Version="0.7.2" />
<PackageReference Include="Webority.Imaging" />
paket add Webority.Imaging --version 0.7.2
#r "nuget: Webority.Imaging, 0.7.2"
#:package Webority.Imaging@0.7.2
#addin nuget:?package=Webority.Imaging&version=0.7.2
#tool nuget:?package=Webority.Imaging&version=0.7.2
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=0looked 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 | Versions 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. |
-
net10.0
- System.IO.Hashing (>= 10.0.13)
- System.Numerics.Tensors (>= 10.0.12)
-
net9.0
- System.IO.Hashing (>= 10.0.13)
- System.Numerics.Tensors (>= 10.0.12)
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.