ParallelPixels 6.0.0

dotnet add package ParallelPixels --version 6.0.0
                    
NuGet\Install-Package ParallelPixels -Version 6.0.0
                    
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="ParallelPixels" Version="6.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ParallelPixels" Version="6.0.0" />
                    
Directory.Packages.props
<PackageReference Include="ParallelPixels" />
                    
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 ParallelPixels --version 6.0.0
                    
#r "nuget: ParallelPixels, 6.0.0"
                    
#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 ParallelPixels@6.0.0
                    
#: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=ParallelPixels&version=6.0.0
                    
Install as a Cake Addin
#tool nuget:?package=ParallelPixels&version=6.0.0
                    
Install as a Cake Tool

ParallelPixels

License: MIT NuGet Build Status Code coverage

ParallelPixels is a fully managed, cross-platform .NET library for decoding, encoding, transforming, and analyzing raster images. It is developed and maintained by Qius Solutions.

The design centers on a strongly typed Image<TPixel> model, pluggable codecs, a fluent processing pipeline (Mutate / Clone), rich metadata profiles, and a configurable memory allocator—suited to server, desktop, cloud, and embedded workloads.

Target framework .NET 10 (net10.0)
NuGet package ParallelPixels
Root namespace ParallelPixels
License MIT

Table of contents

  1. Why ParallelPixels
  2. Installation
  3. Quick start
  4. Core concepts
  5. Loading, identifying, and detecting formats
  6. Saving and encoding
  7. Pixel formats
  8. Supported image formats
  9. Processing pipeline
  10. Transforms
  11. Color filters
  12. Convolution
  13. Effects
  14. Quantization and dithering
  15. Binarization
  16. Drawing and overlays
  17. Normalization
  18. Graphics options and blending
  19. Metadata
  20. Color and color spaces
  21. Configuration and memory
  22. Advanced pixel access
  23. Advanced reference
  24. Common use cases
  25. Building from source
  26. Publishing to NuGet
  27. Repository layout
  28. Community and maintainers

Why ParallelPixels

  • Fully managed — no native dependencies; runs anywhere .NET 10 runs.
  • Typed pixels — work in Rgba32, Rgb24, L8, Rgba64, vectors, and many packed formats without opaque “bitmap” blobs.
  • Codec breadth — JPEG, PNG/APNG, GIF, BMP, TIFF, TGA, WebP, PBM/PGM/PPM, and QOI out of the box.
  • Processing as composition — chain resize, filters, convolution, dithering, drawing, and custom row processors.
  • Production-minded memory — pooled allocators with configurable limits; optional contiguous buffers; decode-time resize to reduce peak RAM.
  • Metadata first-class — EXIF, IPTC, ICC, XMP, CICP, plus format-specific metadata bags.

Installation

dotnet add package ParallelPixels

Primary namespaces:

using ParallelPixels;
using ParallelPixels.PixelFormats;
using ParallelPixels.Processing;
using ParallelPixels.Formats.Jpeg;   // or Png, Gif, Webp, …
using ParallelPixels.Metadata;

Optional MSBuild global usings: set UseParallelPixels to true or enable and import the package’s ParallelPixels.props (ships under the package build/ folder). That adds:

  • ParallelPixels
  • ParallelPixels.PixelFormats
  • ParallelPixels.Processing

Quick start

using ParallelPixels;
using ParallelPixels.Formats.Jpeg;
using ParallelPixels.PixelFormats;
using ParallelPixels.Processing;

// Load → transform → save
using Image<Rgba32> image = Image.Load<Rgba32>("photo.jpg");

image.Mutate(ctx => ctx
    .Resize(new ResizeOptions
    {
        Size = new Size(800, 0),          // width 800, height preserves aspect
        Mode = ResizeMode.Max,
        Sampler = KnownResamplers.Lanczos3
    })
    .GaussianSharpen(1.2f)
    .Brightness(1.05f));

image.Save("out.jpg", new JpegEncoder { Quality = 85 });

// Async decode/encode
await using FileStream input = File.OpenRead("photo.png");
using Image img = await Image.LoadAsync(input);
await img.SaveAsPngAsync("copy.png");

Thumbnail while decoding (less memory):

using Image image = Image.Load(new DecoderOptions
{
    TargetSize = new Size(256, 256),
    Sampler = KnownResamplers.Box
}, "huge.tiff");

Core concepts

Image and Image<TPixel>

Type Role
Image Non-generic base: dimensions, metadata, frames, format-agnostic save helpers.
Image<TPixel> Strongly typed pixel buffer where TPixel : unmanaged, IPixel<TPixel>.
ImageFrame / ImageFrame<TPixel> Single frame (animated GIF/WebP/APNG, multipage TIFF).
ImageFrameCollection / ImageFrameCollection<TPixel> Frame list on an image.
IndexedImageFrame<TPixel> Palettized frame used during quantization.
ImageInfo Lightweight identify result: size, pixel type info, metadata, per-frame metadata—without decoding full pixels.
PixelAccessor<TPixel> Scoped row access helper for advanced scenarios.

Images implement IDisposable. Prefer using so pooled memory returns to the allocator.

Frames and animation

Animated and multipage formats expose multiple frames via image.Frames. Frame and root metadata carry delay, disposal, loop counts, and format-specific fields (GifDisposalMethod, WebP blend/disposal, PNG/APNG blend methods, etc.).

Control how many frames are decoded with DecoderOptions.MaxFrames (default: effectively unlimited; minimum clamped to 1).

Configuration

Configuration controls codecs, parallelism, IO buffering, and memory:

Property Default Purpose
MaxDegreeOfParallelism Environment.ProcessorCount Parallelism for processors (-1 = unlimited via ParallelOptions semantics; must not be 0 or < -1).
StreamProcessingBufferSize 8096 Copy buffer size for stream IO.
PreferContiguousImageBuffers false Prefer single contiguous pixel buffers when size allows.
ReadOrigin ReadOrigin.Current Stream read position strategy for seekable sources.
MemoryAllocator MemoryAllocator.Default Process-wide pool-backed allocator (customize carefully—prefer one busy instance).
ImageFormatsManager preconfigured Registry of detectors, decoders, encoders.
Properties empty concurrent dictionary Extensibility bag for processors/modules.
Configure(IImageFormatConfigurationModule) Register additional format modules.

Default formats registered by Configuration.Default:

PNG, JPEG, GIF, BMP, PBM, TGA, TIFF, WebP, QOI.

Clone configuration with configuration.Clone() when you need a shallow copy sharing the same format manager/allocator.


Loading, identifying, and detecting formats

All load paths accept optional DecoderOptions. Overloads exist for file path, stream, and ReadOnlySpan<byte>, sync and async where IO applies.

DecoderOptions (general)

Property Type Default Meaning
Configuration Configuration Configuration.Default Codecs, allocator, parallelism.
TargetSize Size? null Decode into a size using behavior equivalent to ResizeMode.Max.
Sampler IResampler KnownResamplers.Box Resampler used when TargetSize scales.
SkipMetadata bool false Skip reading encoded metadata.
MaxFrames uint int.MaxValue (clamped ≥ 1) Max frames to decode.

Specialized decoder options

Some formats expose ISpecializedDecoderOptions with GeneralOptions plus format-specific knobs:

Type Extra properties
JpegDecoderOptions ResizeModeJpegDecoderResizeMode: Combined, IdctOnly, ScaleOnly
PngDecoderOptions PngCrcChunkHandling (default IgnoreNonCritical); MaxUncompressedAncillaryChunkSizeBytes (default 8 MB)
WebpDecoderOptions BackgroundColorHandling: Standard / Ignore (animation canvas background)
BmpDecoderOptions RleSkippedPixelHandling (default Black): Black, Transparent, FirstColorOfPalette

Use specialized decoders via Image.Load overloads that take the specialized decoder instance, or register/custom decode pipelines as needed.

Identify vs load vs detect

IImageFormat format = Image.DetectFormat("file.bin");
ImageInfo info = Image.Identify("file.bin");          // headers + metadata, no full raster
using Image image = Image.Load("file.bin");           // boxed Image
using Image<Rgba32> typed = Image.Load<Rgba32>("file.bin");

Async variants: DetectFormatAsync, IdentifyAsync, LoadAsync / LoadAsync<TPixel>.

Raw pixel construction

Image<Rgba32> fromPixels = Image.LoadPixelData<Rgba32>(pixelSpan, width, height);
Image<Rgba32> wrapped = Image.WrapMemory<Rgba32>(memoryOwner, width, height);
// Also: Memory<T>, Span-backed, unmanaged pointers — see Image.WrapMemory overloads.

WrapMemory does not copy; the image views external memory. Lifetime of the owner must outlive (or be transferred carefully with) the Image.


Saving and encoding

Generic save

image.Save("out.png");                          // format inferred from extension via ImageFormatsManager
image.Save(stream, PngFormat.Instance);
image.Save(stream, new PngEncoder { CompressionLevel = PngCompressionLevel.BestCompression });
await image.SaveAsync("out.webp", new WebpEncoder { Quality = 80 });
string b64 = image.ToBase64String(PngFormat.Instance);

Typed SaveAs* helpers

For each built-in format the library ships sync/async overloads for path and stream, with and without an explicit encoder instance:

Method family Encoder type
SaveAsJpeg / SaveAsJpegAsync JpegEncoder
SaveAsPng / SaveAsPngAsync PngEncoder
SaveAsGif / SaveAsGifAsync GifEncoder
SaveAsBmp / SaveAsBmpAsync BmpEncoder
SaveAsTiff / SaveAsTiffAsync TiffEncoder
SaveAsTga / SaveAsTgaAsync TgaEncoder
SaveAsWebp / SaveAsWebpAsync WebpEncoder
SaveAsPbm / SaveAsPbmAsync PbmEncoder
SaveAsQoi / SaveAsQoiAsync QoiEncoder
await image.SaveAsPngAsync("copy.png");
await image.SaveAsJpegAsync(stream, new JpegEncoder { Quality = 85 }, cancellationToken);

Encoder base options

All encoders:

Property Meaning
SkipMetadata Do not write metadata profiles into the bitstream.

Quantizing encoders (QuantizingImageEncoder — PNG palette modes, GIF, BMP indexed, TIFF palette):

Property Default Meaning
Quantizer format-dependent / null IQuantizer (see KnownQuantizers)
PixelSamplingStrategy DefaultPixelSamplingStrategy How pixels are sampled when building palettes

Encode is cancellable via EncodeAsync(..., CancellationToken). Non-seekable streams are buffered through a chunked memory stream using the image’s allocator.


Pixel formats

Pixels live under ParallelPixels.PixelFormats. Naming orders components least → most significant left to right (e.g. in Rgba32, R is the low byte, A the high byte).

Common “working” formats

Type Layout Typical use
Rgba32 8-bit RGBA Default general-purpose
Rgb24 8-bit RGB Opaque photos
Bgra32 / Argb32 / Abgr32 8-bit alternate orders Interop with Windows/GDI-style buffers
Bgr24 8-bit BGR Interop
Rgba64 / Rgb48 16-bit/channel High bit-depth pipelines
L8 / L16 Luminance Grayscale
La16 / La32 Luminance + alpha
A8 Alpha only Masks
RgbaVector Vector4 float HDR / filter math intermediates

Packed / specialty formats

Bgr565, Bgra5551, Bgra4444, Rgba1010102, Rg32, Byte4, Short2, Short4, NormalizedByte2/4, NormalizedShort2/4, HalfSingle, HalfVector2, HalfVector4, and related packed vectors for GPU/interop scenarios.

All implement IPixel<TSelf>; packed types may also implement IPackedVector<TPacked>.

Blending modes (pixel compositing)

Used by drawing/overlays via GraphicsOptions:

Color (PixelColorBlendingMode): Normal, Multiply, Add, Subtract, Screen, Darken, Lighten, Overlay, HardLight

Alpha (PixelAlphaCompositionMode): SrcOver, Src, SrcAtop, SrcIn, SrcOut, Dest, DestAtop, DestOver, DestIn, DestOut, Clear, Xor


Supported image formats

Registered by default on Configuration.Default:

Format Extensions MIME Encoder Decoder notes
JPEG jpg, jpeg, jfif image/jpeg, image/pjpeg JpegEncoder Baseline/progressive family; specialized resize modes
PNG / APNG png, apng image/png, image/apng PngEncoder CRC policy + ancillary chunk size limits
GIF gif image/gif GifEncoder Animation, global/local palettes
BMP bm, bmp, dip image/bmp, image/x-windows-bmp BmpEncoder RLE skip handling on decode
TIFF tiff, tif image/tiff, image/tiff-fx TiffEncoder Broad compression/photometric coverage (see below)
TGA tga, vda, icb, vst image/x-tga, image/x-targa TgaEncoder Optional RLE
WebP webp image/webp WebpEncoder Lossy VP8, lossless VP8L, animation options
PBM family pbm, pgm, ppm portable anymap MIME types PbmEncoder Plain or binary PNM
QOI qoi image/qoi, image/x-qoi, image/vnd.qoi QoiEncoder “Quite OK Image”

JPEG — JpegEncoder / JpegDecoderOptions

Encoder property Type Notes
Quality int? 1–100; when unset → EXIF/JPEG metadata quality if present, else 75 (Quantization.DefaultQualityFactor)
Interleaved bool? When unset → metadata, else true (all components in one scan)
ColorType JpegEncodingColor? When unset → metadata, else YCbCrRatio420
SkipMetadata bool Inherited

JpegEncodingColor: YCbCrRatio420, YCbCrRatio444, YCbCrRatio422, YCbCrRatio411, YCbCrRatio410, Luminance, Rgb, Cmyk, Ycck

Decoder resize strategy (JpegDecoderResizeMode): Combined, IdctOnly, ScaleOnly — choose how IDCT/scale cooperate with DecoderOptions.TargetSize.

image.Save("out.jpg", new JpegEncoder
{
    Quality = 90,
    ColorType = JpegEncodingColor.YCbCrRatio420,
    Interleaved = true
});

PNG — PngEncoder / PngDecoderOptions

Encoder property Type Default / notes
BitDepth PngBitDepth? Bit1, Bit2, Bit4, Bit8, Bit16
ColorType PngColorType? Grayscale, Rgb, Palette, GrayscaleWithAlpha, RgbWithAlpha
FilterMethod PngFilterMethod? None, Sub, Up, Average, Paeth, Adaptive
CompressionLevel PngCompressionLevel DefaultCompression (= Level6); Level0Level9 / BestSpeed / BestCompression
TextCompressionThreshold int 1024 — compress text metadata above this length
Gamma float? Optional gAMA
Threshold byte Transparency threshold (byte.MaxValue)
InterlaceMethod PngInterlaceMode? None, Adam7
ChunkFilter PngChunkFilter? Flags: exclude physical/gamma/exif/text/all
TransparentColorMode PngTransparentColorMode Preserve / Clear (force transparent black for better compression)
Quantizer / PixelSamplingStrategy from base Used for palette encoding

Decoder: PngCrcChunkHandlingIgnoreNone, IgnoreNonCritical (default), IgnoreData, IgnoreAll; MaxUncompressedAncillaryChunkSizeBytes default 8 MB.

GIF — GifEncoder

Property Notes
ColorTableMode GifColorTableMode?: Global or Local
Quantizer Palette generation for truecolor sources

Animation timing/disposal live in frame/root metadata (GifDisposalMethod: Unspecified, NotDispose, RestoreToBackground, RestoreToPrevious).

BMP — BmpEncoder / BmpDecoderOptions

Encoder property Notes
BitsPerPixel BmpBitsPerPixel?: Pixel1, Pixel2, Pixel4, Pixel8, Pixel16, Pixel24, Pixel32
SupportTransparency With 32 bpp, writes BITFIELDS V4 header instead of classic V3
Quantizer Default KnownQuantizers.Octree for indexed depths

Decoder RLE skipped pixels: Black, Transparent, FirstColorOfPalette.

TIFF — TiffEncoder

Property Notes
BitsPerPixel Bit1Bit64 subset enum (Bit1, Bit4, Bit6, Bit8, … Bit64)
Compression See compression table
CompressionLevel Deflate levels via DeflateCompressionLevel
PhotometricInterpretation RGB / palette / gray / bi-level preferred for encode
HorizontalPredictor None, Horizontal, FloatingPoint — helps LZW/Deflate
Quantizer Default KnownQuantizers.Octree

Compression support (library notes):

Compression Encode Decode
None
PackBits
LZW
Deflate
Old Deflate
Ccitt1D / Group3 / Group4
JPEG (TechNote 2)
Old JPEG ✓ (chunky)
WebP-in-TIFF

Photometric (high level): encode focuses on WhiteIsZero, BlackIsZero, RGB (chunky), PaletteColor. Decode additionally covers planar RGB, Separated, YCbCr, CieLab, CMYK, tiled images, etc. Multipage decode currently expects frames of equal dimensions.

TGA — TgaEncoder

Property Default Notes
BitsPerPixel inferred Pixel8, Pixel16, Pixel24, Pixel32
Compression RunLength or None

WebP — WebpEncoder / WebpDecoderOptions

Property Default Notes
FileFormat lossy if unset WebpFileFormatType.Lossy / Lossless
Quality 75 Lossy: size↔quality; Lossless: effort 0–100
Method Default (= Level4) Level0/FastestLevel6/BestQuality
UseAlphaCompression true Lossless alpha plane
EntropyPasses 1 Range 1–10
SpatialNoiseShaping 50 0–100
FilterStrength 60 Deblocking strength 0–100
TransparentColorMode Clear or Preserve
NearLossless false Near-lossless preprocessing
NearLosslessQuality 100 0–100

Animation background: BackgroundColorHandling.Standard or Ignore.

PBM / PGM / PPM — PbmEncoder

Property Values
Encoding Plain, Binary
ColorType BlackAndWhite, Grayscale, Rgb
ComponentType Bit, Byte, Short

QOI — QoiEncoder

Property Notes
Channels Rgb (3) or Rgba (4) — informative header field
ColorSpace SrgbWithLinearAlpha or AllChannelsLinear — informative

QoiDecoder is internal; consumers still decode via Image.Load / LoadAsync (the format module registers the decoder). There is no public Decode API on Image—use Load / Identify / DetectFormat.


Processing pipeline

All geometric and pixel processors hang off IImageProcessingContext.

// In-place
image.Mutate(ctx => ctx.Resize(800, 600).Grayscale());

// Non-destructive
using Image<Rgba32> copy = image.Clone(ctx => ctx.DetectEdges());

// Explicit configuration
image.Mutate(customConfig, ctx => ctx.GaussianBlur(3));

// Explicit processor instances
image.Mutate(new ResizeProcessor(new ResizeOptions { Size = new Size(100, 100) }, image.Size));

Most operations also accept an optional Rectangle to limit the source region. Filters that change dimensions (resize, crop, pad, rotate orthogonal, etc.) update the working image size as they run in the chain.


Transforms

Resize

ctx.Resize(800, 600);
ctx.Resize(800, 600, KnownResamplers.Lanczos3);
ctx.Resize(new ResizeOptions { /* … */ });

ResizeOptions

Property Default Meaning
Mode Crop See modes below
Position Center Anchor when cropping/padding
CenterCoordinates null Optional focal point
Size Target size (0 on one axis preserves aspect in several overloads)
Sampler Bicubic IResampler
Compand false Gamma compress/expand during resize
TargetRectangle null Destination rect inside working buffer
PremultiplyAlpha true Premultiply during resampling
PadColor transparent/default Background when padding

ResizeMode

Mode Behavior
Crop Scale to cover target, crop overflow
Pad Scale to fit, pad remainder
BoxPad Pad without upscaling source (downscale acts like Pad)
Max Fit inside target, keep aspect
Min Grow until shortest side matches; no upscaling
Stretch Ignore aspect
Manual Exact target rect supplied

AnchorPositionMode: Center, Top, Bottom, Left, Right, TopLeft, TopRight, BottomRight, BottomLeft

KnownResamplers: Bicubic, Box, CatmullRom, Hermite, Lanczos2/3/5/8, MitchellNetravali, NearestNeighbor, Robidoux, RobidouxSharp, Spline, Triangle (bilinear), Welch

Crop, pad, entropy crop

  • Crop(Rectangle) / Crop(width, height) — exact region
  • EntropyCrop() / EntropyCrop(float threshold) — trim low-entropy borders (default threshold 0.5)
  • Pad(int width, int height) / with Color — expand canvas (ResizeMode.BoxPad)

Rotate / flip / auto-orient

  • Rotate(degrees) — arbitrary angle (resampling)
  • Rotate(RotateMode)None, Rotate90, Rotate180, Rotate270 (orthogonal, no resample)
  • Flip(FlipMode)None, Horizontal, Vertical
  • RotateFlip(...) — combined
  • AutoOrient() — apply EXIF orientation then clear the tag

Skew, affine, projective, swizzle

  • Skew(degreesX, degreesY) (+ rectangle overloads)
  • Transform(AffineTransformBuilder) — compose scale, rotate, skew, translate, matrices
  • Transform(ProjectiveTransformBuilder) — adds taper (TaperSide / TaperCorner) and projective matrices
  • Swizzle(ISwizzler) — pixel permutation patterns

AffineTransformBuilder / ProjectiveTransformBuilder support Prepend* and Append* for rotation (degrees/radians), scale, skew, translation, and raw matrices; BuildMatrix(Size|Rectangle) and GetTransformedSize(...). Optional TransformSpace selects coordinate interpretation.


Color filters

Applied as color-matrix / channel operations on IImageProcessingContext (most have rectangle overloads):

Method Parameters / notes
Brightness(float) Multiplier
Contrast(float) Multiplier
Saturate(float) Multiplier
Hue(float degrees) Rotation in hue
Lightness(float)
Opacity(float)
Invert()
Grayscale() / Grayscale(GrayscaleMode) Bt709, Bt601
BlackWhite()
Sepia()
Kodachrome(), Lomograph(), Polaroid() Photographic matrices
ColorBlindness(ColorBlindnessMode) See below
Filter(ColorMatrix) Custom matrix via FilterExtensions

ColorBlindnessMode: Achromatomaly, Achromatopsia, Deuteranomaly, Deuteranopia, Protanomaly, Protanopia, Tritanomaly, Tritanopia

Reusable matrices also appear on KnownFilterMatrices.


Convolution

Method Key parameters
GaussianBlur sigma; optional Rectangle; optional BorderWrappingMode for X/Y
GaussianSharpen same shape as GaussianBlur
BoxBlur radius; optional rect + BorderWrappingMode X/Y
MedianBlur radius, preserveAlpha
BokehBlur radius, components, gamma
DetectEdges kernel + optional grayscale / rect

BorderWrappingMode (edge sampling for separable blurs): Repeat, Wrap, Mirror, Bounce

KnownEdgeDetectorKernels: Kayyali, Kirsch, Laplacian3x3, Laplacian5x5, LaplacianOfGaussian, Prewitt, RobertsCross, Robinson, Scharr, Sobel

Kernels split into 2D, compass, and isotropic families—overloads accept the matching kernel type.


Effects

Method Notes
Pixelate() / Pixelate(int size) Default size 4; optional rectangle
OilPaint() / OilPaint(int levels, int brushSize) Defaults levels=10, brushSize=15
ProcessPixelRowsAsVector4(PixelRowOperation) Custom per-row Span<Vector4> processing; modifiers for premultiply/compand/scale; position-aware PixelRowOperation<Point> overloads

Quantization and dithering

Quantize

ctx.Quantize();                              // KnownQuantizers.Octree
ctx.Quantize(KnownQuantizers.Wu);
ctx.Quantize(quantizer, rectangle);

KnownQuantizers

Name Role
Octree Fast adaptive octree
Wu Xiaolin Wu — high quality
WebSafe CSS Color Module Level 4 web-safe palette
Werner Werner’s Nomenclature palette

Encoders for GIF/BMP/TIFF palette modes consume the same IQuantizer infrastructure.

Dither

ctx.Dither();                                // KnownDitherings.Bayer8x8
ctx.Dither(KnownDitherings.FloydSteinberg);
ctx.Dither(quantizer, dither);

KnownDitherings

Ordered: Bayer2x2, Ordered3x3, Bayer4x4, Bayer8x8, Bayer16x16

Error diffusion: Atkinson, Burks, FloydSteinberg, JarvisJudiceNinke, Sierra2, Sierra3, SierraLite, StevensonArce, Stucki


Binarization

Method Notes
BinaryThreshold(float threshold) Plus mode, colors, rectangle overloads
BinaryDither(IDither) Threshold + dither
AdaptiveThreshold(...) Integral-image adaptive; optional upper/lower colors, thresholdLimit, rectangle

BinaryThresholdMode: Luminance (BT.709), Saturation, MaxChroma (YCbCr)


Drawing and overlays

Draw image

ctx.DrawImage(otherImage, new Point(10, 20), 0.5f);
ctx.DrawImage(otherImage, rectangle, graphicsOptions);

Opacity, source/destination rectangles, and full GraphicsOptions overloads are available.

Overlays

Method Notes
BackgroundColor(Color) Fill background (rect optional)
Glow(Color) / radius / GraphicsOptions Soft glow
Vignette(Color) / radii / options Vignette burn

Normalization

Histogram equalization and leveling:

ctx.HistogramEqualization();
ctx.HistogramEqualization(new HistogramEqualizationOptions
{
    Method = HistogramEqualizationMethod.AdaptiveTileInterpolation,
    LuminanceLevels = 256,
    ClipHistogram = true,
    ClipLimit = 350,
    NumberOfTiles = 8,
    SyncChannels = true
});

HistogramEqualizationMethod: Global, AdaptiveTileInterpolation, AdaptiveSlidingWindow, AutoLevel

Option Default Meaning
Method Global Algorithm family
LuminanceLevels 256 Histogram bins
ClipHistogram false CLAHE-style clipping
ClipLimit 350 Clip threshold when enabled
NumberOfTiles 8 Tiles for adaptive modes
SyncChannels true Keep RGB channels synchronized

Graphics options and blending

GraphicsOptions influences drawing and overlays:

Property Default Notes
Antialias true
AntialiasSubpixelDepth 16 ≥ 0
BlendPercentage 1 0…1 opacity of the operation
ColorBlendingMode Normal See pixel blending modes
AlphaCompositionMode SrcOver Porter–Duff style

Defaults can be adjusted via GraphicOptionsDefaultsExtensions:

// Per processing context
ctx.SetGraphicsOptions(o => { o.BlendPercentage = 0.5f; o.Antialias = false; });
GraphicsOptions current = ctx.GetGraphicsOptions();

// Process-wide defaults on Configuration
config.SetGraphicsOptions(new GraphicsOptions { ColorBlendingMode = PixelColorBlendingMode.Multiply });

Metadata

Attached to Image.Metadata (ImageMetadata) and per-frame ImageFrameMetadata.

Resolution

Member Default
HorizontalResolution / VerticalResolution 96
ResolutionUnits PixelResolutionUnit.PixelsPerInch

Profiles

Property Profile
ExifProfile EXIF tags (orientation, camera, GPS, …)
IptcProfile IPTC-IIM editorial fields
IccProfile ICC color management
XmpProfile XMP packet bytes/XML
CicpProfile CICP coding-independent code points (HDR/video color signaling)
DecodedImageFormat Format detected at decode (informational)

Format-specific bags: GetFormatMetadata / TryGetFormatMetadata keyed by IImageFormat<TFormatMetadata> (PNG textual chunks, GIF animation root data, WebP animation, TIFF IFD-derived data, etc.).

AutoOrient() consumes EXIF orientation. Encoders honor SkipMetadata to strip profiles on write.


Color and color spaces

ParallelPixels.Color

Color is a lossless working color (internally expanded) with:

  • Factories: FromRgba, FromRgb, FromPixel<TPixel>, Parse / ParseHex, TryParse*
  • WithAlpha, ToHex, ToPixel<TPixel>, bulk ToPixel spans
  • Named colors and palettes (Color.NamedColors, web-safe, Werner)

ParallelPixels.ColorSpaces

Structural color spaces for conversion pipelines, including:

Rgb, LinearRgb, Cmyk, YCbCr, Hsl, Hsv, CieXyz, CieLab, CieLch, CieLchuv, CieLuv, CieXyy, HunterLab, Lms, plus illuminants, working spaces, and companding helpers.

Use ColorSpaceConverter (with ColorSpaceConverterOptions for white points, target RGB working space, and chromatic adaptation) for explicit ToXxx / span Convert / Adapt pipelines—beyond simple pixel casts. Illuminants include A–E, D50–D75, F2/F7/F11; working spaces include sRGB, Rec.709, Rec.2020, Adobe RGB, ProPhoto, and others.


Configuration and memory

Custom configuration example

Configuration config = Configuration.Default.Clone();
config.MaxDegreeOfParallelism = 4;
config.PreferContiguousImageBuffers = true;
config.MemoryAllocator = MemoryAllocator.Create(new MemoryAllocatorOptions
{
    MaximumPoolSizeMegabytes = 128,
    AllocationLimitMegabytes = 1024
});

using Image<Rgba32> image = Image.Load<Rgba32>(new DecoderOptions { Configuration = config }, path);

MemoryAllocatorOptions

Property Meaning
MaximumPoolSizeMegabytes Cap on retained pool size (null = platform default)
AllocationLimitMegabytes Max discontiguous allocation (null → ~1 GB on 32-bit, ~4 GB on 64-bit)

MemoryAllocator.Create() builds the default pooled unmanaged allocator. Call ReleaseRetainedResources() only after disposing associated images when tearing down a custom allocator.

Guidance: allocators are expensive—prefer one process-wide instance (Configuration.Default.MemoryAllocator = …) rather than per-request pools.


Advanced pixel access

image.ProcessPixelRows(accessor =>
{
    for (int y = 0; y < accessor.Height; y++)
    {
        Span<Rgba32> row = accessor.GetRowSpan(y);
        // mutate row
    }
});

image.Mutate(ctx => ctx.ProcessPixelRowsAsVector4(span =>
{
    for (int i = 0; i < span.Length; i++)
        span[i] *= 0.9f;
}));

Lower-level parallelism utilities live under ParallelPixels.Advanced (ParallelRowIterator) for custom processors. Prefer public Mutate extensions unless you are authoring an IImageProcessor.


Advanced reference

This section covers remaining public APIs that operators often need once past the happy path.

Constructing images and converting pixel types

using Image<Rgba32> blank = new(800, 600);
using Image<Rgba32> filled = new(800, 600, Color.White.ToPixel<Rgba32>());
using Image<Rgba32> configured = new(config, 800, 600, background);

// Deep clone same pixel type
using Image<Rgba32> copy = image.Clone();

// Convert all frames to another pixel format (new image)
using Image<Bgra32> bgra = image.CloneAs<Bgra32>();
using Image<L8> gray = image.CloneAs<L8>(customConfig);

CloneAs<TPixel2> allocates a new typed image and converts every frame. Use it for interop (e.g. Bgra32 for Windows buffers) or bit-depth changes (Rgba64Rgba32).

Creating images from memory

Besides LoadPixelData / WrapMemory (see Loading):

API Copies? Ownership
LoadPixelData<TPixel>(span, w, h) Yes Image owns new buffer
WrapMemory<TPixel>(Memory<T> / IMemoryOwner<T> / byte memory / void*) No Caller must keep buffer alive; owners can transfer lifetime carefully

Stream read origin

Configuration.ReadOrigin:

Value Behavior
Current (default) Read from the stream’s current position
Begin Seek to the start before reading (seekable streams)

Integral images

Used by adaptive thresholding and custom algorithms:

using Buffer2D<ulong> integral = image.CalculateIntegralImage();
using Buffer2D<ulong> region = image.CalculateIntegralImage(new Rectangle(10, 10, 100, 100));
// Also: image.Frames.RootFrame.CalculateIntegralImage(...)

Returns a Buffer2D<ulong> (dispose / return via normal buffer lifetime rules tied to the allocator).

Pixel row conversion modifiers

ProcessPixelRowsAsVector4 accepts PixelConversionModifiers (flags):

Flag Meaning
None Raw scaled vectors as stored
Scale Scale to/from 0–1 working range as applicable
Premultiply Premultiply / unpremultiply alpha around the operation
SRgbCompand Compact/expand sRGB gamma around the operation

Combine with |. Position-aware overload: PixelRowOperation<Point> receives the row origin.

Quantizer options and custom quantizers

KnownQuantizers.* are convenience instances. For control, construct quantizers with QuantizerOptions:

var options = new QuantizerOptions
{
    MaxColors = 64,                              // clamped 1..256 (default 256)
    Dither = KnownDitherings.FloydSteinberg,     // default; set null to disable
    DitherScale = 0.75f,                         // 0..1 (default 1)
    ColorMatchingMode = ColorMatchingMode.Exact  // Coarse (default) | Hybrid | Exact
};

IQuantizer wu = new WuQuantizer(options);
IQuantizer octree = new OctreeQuantizer(options);
IQuantizer customPalette = new PaletteQuantizer(paletteColors, options);
// Also: WebSafePaletteQuantizer(options), WernerPaletteQuantizer(options)

image.Mutate(ctx => ctx.Quantize(wu));

// Encoders that quantize:
new GifEncoder
{
    Quantizer = wu,
    PixelSamplingStrategy = new ExtensivePixelSamplingStrategy()
};

IPixelSamplingStrategy

Type Behavior
DefaultPixelSamplingStrategy Caps work (~4096² pixels default) with a minimum scan ratio (default 0.1); configurable via ctor (maximumPixels, minimumScanRatio)
ExtensivePixelSamplingStrategy Enumerates full frame regions — more accurate palettes, more CPU

KnownFilterMatrices

Static photographic / accessibility matrices and factories (usable with ctx.Filter(matrix)):

  • Filters: AchromatomalyFilter, AchromatopsiaFilter, DeuteranomalyFilter, DeuteranopiaFilter, ProtanomalyFilter, ProtanopiaFilter, TritanomalyFilter, TritanopiaFilter, BlackWhiteFilter, KodachromeFilter, LomographFilter, PolaroidFilter
  • Factories: CreateBrightnessFilter, CreateContrastFilter, CreateGrayscaleBt601Filter, CreateGrayscaleBt709Filter, CreateHueFilter, CreateInvertFilter, CreateOpacityFilter, CreateSaturateFilter, CreateLightnessFilter, CreateSepiaFilter

Animation metadata (GIF / APNG / WebP)

Root and per-frame bags are retrieved via format helpers:

GifMetadata gif = image.Metadata.GetGifMetadata();
GifFrameMetadata frame = image.Frames[0].Metadata.GetGifMetadata();

PngMetadata png = image.Metadata.GetPngMetadata();   // RepeatCount, AnimateRootFrame, …
WebpMetadata webp = image.Metadata.GetWebpMetadata();

Also: TryGetGifMetadata / TryGetPngMetadata / TryGetWebpMetadata (+ frame variants).

Format Root fields (high level) Frame fields (high level)
GIF RepeatCount, ColorTableMode, GlobalColorTable, BackgroundColorIndex, Comments FrameDelay, DisposalMethod, local table, transparency index
PNG/APNG RepeatCount, AnimateRootFrame, bit depth/color type, gamma, text, color table FrameDelay (Rational), DisposalMethod, BlendMethod
WebP FileFormat, RepeatCount, BackgroundColor FrameDelay, BlendMethod, DisposalMethod

Disposal / blend enums:

  • GIF GifDisposalMethod: Unspecified, NotDispose, RestoreToBackground, RestoreToPrevious
  • PNG PngDisposalMethod: DoNotDispose, RestoreToBackground, RestoreToPrevious; PngBlendMethod: Source, Over
  • WebP WebpDisposalMethod: DoNotDispose, RestoreToBackground; WebpBlendMethod: Over, Source

Manage frames with image.Frames: AddFrame, InsertFrame, RemoveFrame, MoveFrame, CloneFrame, ExportFrame, CreateFrame, indexer, RootFrame, Count.

Memory allocator variants

API Visibility Role
MemoryAllocator.Default / Create(options) public Process-wide pooled unmanaged allocator (implementation internal)
SimpleGcMemoryAllocator public Allocates fresh managed arrays; no pool — useful for diagnostics or tiny tools
Pool implementation types internal Not part of the public contract
config.MemoryAllocator = new SimpleGcMemoryAllocator();
// or
config.MemoryAllocator = MemoryAllocator.Create(new MemoryAllocatorOptions
{
    MaximumPoolSizeMegabytes = 64,
    AllocationLimitMegabytes = 512
});

Geometry helpers

GeometryUtilities.DegreeToRadian(float) / RadianToDegree(float) — small helpers used when composing transforms manually.

Image format manager (custom codecs)

config.ImageFormatsManager.SetEncoder(PngFormat.Instance, new PngEncoder { CompressionLevel = PngCompressionLevel.BestCompression });
config.ImageFormatsManager.SetDecoder(JpegFormat.Instance, JpegDecoder.Instance);
config.ImageFormatsManager.TryFindFormatByFileExtension("webp", out IImageFormat? fmt);
config.Configure(new MyCustomFormatModule()); // IImageFormatConfigurationModule

Projective / affine transform spaces

TransformSpace on builders: Pixel (default) or Coordinate — controls how matrix math interprets the source rectangle when building. Projective builders add PrependTaper / AppendTaper(TaperSide, TaperCorner, fraction) for perspective-like tapers (TaperSide: Left/Top/Right/Bottom; TaperCorner: LeftOrTop/RightOrBottom/Both).

Platform note (iOS / AOT)

Generic-heavy paths (notably GIF quantization/encoding) can stress ahead-of-time compilers. The library contains internal AOT seeding tooling under ParallelPixels.Advanced for Xamarin/.NET iOS scenarios. Typical desktop/server consumers never need it; if you hit AOT JIT errors around palette construction, consult the library’s advanced/AOT guidance in source comments.

Full public pixel struct list

A8, Abgr32, Argb32, Bgr24, Bgr565, Bgra32, Bgra4444, Bgra5551, Byte4, HalfSingle, HalfVector2, HalfVector4, L8, L16, La16, La32, NormalizedByte2, NormalizedByte4, NormalizedShort2, NormalizedShort4, Rg32, Rgb24, Rgb48, Rgba1010102, Rgba32, Rgba64, RgbaVector, Short2, Short4.

Built-in formats use unassociated (straight) alpha or no alpha—not premultiplied storage in the pixel type itself (premultiply is applied transiently during some processors when requested).


Common use cases

1. Image CDN / thumbnail service

Decode with TargetSize, use ResizeMode.Max or Crop with Lanczos, encode JPEG/WebP with explicit quality. Cap MaxDegreeOfParallelism per host CPU. Use a single customized MemoryAllocator for the process.

2. User avatar pipeline

Load → AutoOrientResize square with ResizeMode.Crop + AnchorPositionMode.Center → optional GaussianSharpen → PNG or WebP.

3. Document / FAX TIFF

Decode TIFF (Group4/G3 supported) → BinaryThreshold or keep 1-bit → encode TIFF with CcittGroup4Fax or PNG for web preview.

4. Transparent product shots

Prefer Rgba32 → resize with PremultiplyAlpha = true → WebP lossless or PNG with TransparentColorMode = Clear for compression.

5. Palette GIF animation

Compose frames on Image<Rgba32>, set frame metadata delays/disposal, encode with GifEncoder + KnownQuantizers.Wu and optional FloydSteinberg.

6. Scientific / high bit depth

Work in Rgba64 or L16, use Compand = true on resize when exchanging with gamma-encoded 8-bit outputs, export TIFF 16-bit or PNG Bit16.

7. Content moderation / edge features

Mutate(x => x.Grayscale().DetectEdges(KnownEdgeDetectorKernels.Sobel)) as a cheap feature map; or ProcessPixelRowsAsVector4 for custom scores.

8. Interop with existing buffers

Image.WrapMemory<Bgra32>(owner, width, height) over Windows-style buffers; encode without an extra copy when layouts match.


Building from source

Prerequisites

git clone https://github.com/qius-solutions/parallel-pixels.git
cd parallel-pixels
git lfs pull
dotnet build ParallelPixels.sln -c Debug -p:RunAnalyzers=false

Notes:

  • Release builds may treat StyleCop/analyzers as errors; use -p:RunAnalyzers=false while iterating.
  • Optional blame ignore: git config blame.ignoreRevsFile .git-blame-ignore-revs
  • On Windows, enable long paths: git config --system core.longpaths true

Guard / ThrowHelper unit tests:

dotnet test tests/SharedInfrastructure.Tests/SharedInfrastructure.Tests.csproj -c Debug

Publishing to NuGet

Pack (from the repository root):

dotnet pack src/ParallelPixels/ParallelPixels.csproj -c Release \
  -p:PackageVersion=<VERSION> \
  -p:PackageOutputPath=./artifacts \
  -p:TreatWarningsAsErrors=false

Push:

dotnet nuget push ./src/ParallelPixels/artifacts/ParallelPixels.<VERSION>.nupkg \
  --api-key <YOUR_TOKEN> \
  --source https://api.nuget.org/v3/index.json

Replace <VERSION> (e.g. 1.0.0) and <YOUR_TOKEN> with your NuGet.org API key. The pack command writes the .nupkg under the project’s artifacts/ output path used above.


Repository layout

Path Purpose
ParallelPixels.sln, Directory.Build.* Solution + shared MSBuild
msbuild/ QiusSolutions.* props/targets, rulesets, StyleCop, signing key
src/ParallelPixels/ Library: Formats/, PixelFormats/, Processing/, Metadata/, Memory/, Color*, compression, Common/Helpers (Guard, ThrowHelper)
tests/ParallelPixels.Tests/ Unit tests + fixtures
tests/SharedInfrastructure.Tests/ Guard / DebugGuard tests
tests/ParallelPixels.Benchmarks/ BenchmarkDotNet
tests/ParallelPixels.Tests.ProfilingSandbox/ Manual profiling host
tests/Images/ Reference images (Git LFS)
ParallelPixels.props Optional consumer global usings

Codec-specific engineering notes live beside sources, e.g. src/ParallelPixels/Formats/Tiff/README.md, Formats/Jpeg/README.md, PixelFormats/README.md.


Community and maintainers

Maintainer: Qius Solutions — contributions welcome under the MIT license.

Product Compatible and additional computed target framework versions.
.NET 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.
  • net10.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
6.0.0 107 8/6/2026
5.0.0 93 8/6/2026
4.0.0 105 8/6/2026
3.0.0 104 8/6/2026
2.0.0 96 8/6/2026
1.0.0 126 5/13/2026
0.0.1 111 5/13/2026