Class RasterOps
- Namespace
- Egami.Operations
- Assembly
- Egami.dll
Animation steps: they work on the frames of the whole animation rather than on each frame, so they run in Apply, Derive and Transcode (which then decodes the whole animation first) but not inside Within. Frames in memory are already full pictures of what is on screen, so there is no Coalesce, and the writers find each frame's changed area themselves, so there is no Optimize.
public sealed class RasterOps
- Inheritance
-
RasterOps
- Inherited Members
- Extension Methods
Examples
raster.Apply(ops => ops.Add(new MyOperation()));
Methods
AdaptiveThreshold(float, int?, Rgba8?, Rgba8?)
Thresholds each pixel against the mean of the window around it (Bradley and Roth, 2007): a
pixel is dark when its luminance is more than limit below its window's mean, so uneven lighting on a scanned
page does not swallow text. Alpha is kept.
public RasterOps AdaptiveThreshold(float limit = 0.15, int? window = null, Rgba8? below = null, Rgba8? above = null)
Parameters
limitfloatHow far below the local mean a pixel must be to count as dark, from 0 to 1. Defaults to 0.15.
windowint?The window's side in pixels, at least 1, or null (the default) for an eighth of the width.
belowRgba8?The dark color, or null for black.
aboveRgba8?The light color, or null for white.
Returns
- RasterOps
This builder.
Examples
// Threshold a scanned page for OCR: Otsu's level for an evenly lit page, or Bradley's local threshold for uneven light.
float level = page.FindThreshold(ThresholdMethod.Otsu);
using Raster<Gray8> even = page.Derive(o => o.AutoThreshold(ThresholdMethod.Otsu), Ct);
using Raster<Gray8> uneven = page.Derive(o => o.AdaptiveThreshold(limit: 0.15f), Ct);
Remarks
A luminance plane, 4 bytes a pixel, counts against MaxTotalBytes. Inside a rectangle or mask, the scope is its image.
Exceptions
- ArgumentOutOfRangeException
An argument is out of range.
Add(IRasterOperation)
Adds a step, such as a custom IRasterOperation.
public RasterOps Add(IRasterOperation operation)
Parameters
operationIRasterOperationThe operation.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentNullException
operationis null.
AddNoise(NoiseKind, float, bool, ulong)
Adds noise to red, green and blue (or a CMYK raster's inks), as ImageMagick's +noise with -attenuate does: film grain, sensor noise, or salt and pepper for testing filters. Alpha is never touched. The same seed gives the same pixels on any machine and at any thread count, and inside a scope an area gets the noise the whole image would get there.
public RasterOps AddNoise(NoiseKind kind, float amount = 1, bool monochrome = false, ulong seed = 0)
Parameters
kindNoiseKindThe kind of noise.
amountfloatThe strength, as ImageMagick's -attenuate, from 0 (changes nothing) to 10; 1 gives ImageMagick's default.
monochromeboolWhether red, green and blue get the same noise, so it has no color.
seedulongThe seed: change it for different noise.
Returns
- RasterOps
This builder.
Examples
// Film grain: gray Gaussian noise at a third of ImageMagick's default strength; the same seed gives the same grain.
photo.Apply(ops => ops.AddNoise(NoiseKind.Gaussian, 0.3f, monochrome: true, seed: 42), Ct);
Exceptions
- ArgumentOutOfRangeException
kindis not defined, oramountis outside 0..10.
AlphaToGray()
Makes the image a gray picture of its alpha: red, green and blue become the alpha value and alpha becomes opaque, as ImageMagick's -alpha extract does. A color matrix, so it fuses with neighbouring color steps.
public RasterOps AlphaToGray()
Returns
- RasterOps
This builder.
Examples
using Raster alpha = photo.Derive(ops => ops.AlphaToGray(), Ct); // see the transparency as gray
using Raster cutout = photo.Derive(ops => ops.CopyAlpha(new Mask(matte)), Ct); // a gray image becomes the alpha
using Raster onWhite = cutout.Derive(ops => ops.Flatten(Rgba8.White), Ct); // composite onto white, opaque
using Raster luma = photo.Derive(ops => ops.LuminanceToAlpha(), Ct); // brightness becomes alpha
ApplyFilter(ColorFilter)
Runs a ColorFilter on every pixel. Adjacent filters, tone steps and color matrices run as one pass over the image, clamping between steps as running them one by one would.
public RasterOps ApplyFilter(ColorFilter filter)
Parameters
filterColorFilterThe filter.
Returns
- RasterOps
This builder.
Examples
// A look as a value: build it once, mix it in at 70%, apply it to any image or to your own pixels.
ColorFilter look = ColorFilter.Level(0.03f, 0.97f).Then(ColorFilter.Saturation(1.2f)).Then(ColorFilter.Tint(new Rgba8(255, 190, 140, 255), 0.2f));
ColorFilter subtle = ColorFilter.Lerp(ColorFilter.Identity, look, 0.7f);
raster.Apply(o => o.ApplyFilter(subtle), Ct);
Span<Rgba8> swatch = [new Rgba8(200, 120, 80, 255), new Rgba8(40, 60, 90, 255)];
subtle.Apply(swatch);
Exceptions
- ArgumentNullException
filteris null.
Arithmetic(PixelMath, float, ColorChannels)
Applies op with value to every value of channels, on values scaled 0 to 1
and clamped back to 0..1, as ImageMagick's -evaluate defines each operator. 8-bit and 16-bit pixels are evaluated as 16-bit
samples and rounded as ImageMagick's Q16 build rounds them, through a table per call, so results are identical to -evaluate.
public RasterOps Arithmetic(PixelMath op, float value, ColorChannels channels = ColorChannels.Color)
Parameters
opPixelMathThe operator.
valuefloatThe constant, on the same 0 to 1 scale for Add, Subtract, Min, Max and Set.
channelsColorChannelsThe channels to change. Defaults to Color; alpha changes only when included.
Returns
- RasterOps
This builder.
Examples
// Lift the shadows with a log curve, then cap the highlights; values are on a 0 to 1 scale, as ImageMagick's -evaluate.
photo.Apply(ops => ops
.Arithmetic(PixelMath.Log, 3)
.Arithmetic(PixelMath.Min, 0.95f), Ct);
Exceptions
- ArgumentOutOfRangeException
opis not defined,valueis not finite, orchannelsholds values that are not channels.
AutoGamma(bool, bool)
Applies the Gamma(float) that moves the image's mean to 0.5, as ImageMagick's -auto-gamma; an image whose mean is 0 or 1 is left alone. Measured like AutoLevel(bool, bool).
public RasterOps AutoGamma(bool linked = true, bool perFrame = false)
Parameters
linkedboolWhether the channels share one gamma from their joint mean (the default) or each gets its own.
perFrameboolWhether each frame is measured alone.
Returns
- RasterOps
This builder.
Examples
// Fix a dull scan: stretch it to the full range, clipping the darkest 2% and lightest 1%, then set the midtones.
raster.Apply(o => o.Normalize().AutoGamma(), Ct);
// Or stretch each channel on its own, which also removes a cast.
raster.Apply(o => o.AutoLevel(linked: false), Ct);
// Measured steps measure only their scope: here the sky alone is stretched.
raster.Apply(o => o.Within(new Rect(0, 0, raster.Width, raster.Height / 3), sky => sky.AutoLevel()), Ct);
AutoLevel(bool, bool)
Stretches the darkest value to 0 and the lightest to 1, as ImageMagick's -auto-level. The chain runs up to this step, the result is measured, and the step becomes a Level(float, float, float, float, float); inside Within(Rect, Action<RasterOps>), Within(Mask, Action<RasterOps>) or OnChannels(ColorChannels, Action<RasterOps>) only that scope is measured. Transparent pixels do not count.
public RasterOps AutoLevel(bool linked = true, bool perFrame = false)
Parameters
linkedboolWhether red, green and blue share one black and one white point (the default, which keeps colors), or each gets its own, which also removes a cast.
perFrameboolWhether each frame is measured alone, as ImageMagick does, instead of all frames together so an animation does not flicker.
Returns
- RasterOps
This builder.
Examples
// Fix a dull scan: stretch it to the full range, clipping the darkest 2% and lightest 1%, then set the midtones.
raster.Apply(o => o.Normalize().AutoGamma(), Ct);
// Or stretch each channel on its own, which also removes a cast.
raster.Apply(o => o.AutoLevel(linked: false), Ct);
// Measured steps measure only their scope: here the sky alone is stretched.
raster.Apply(o => o.Within(new Rect(0, 0, raster.Width, raster.Height / 3), sky => sky.AutoLevel()), Ct);
AutoOrient()
Turns the image the way its EXIF orientation says, so it looks as the camera meant, and sets the orientation to Normal. Each orientation is one exact pass (a flip, a quarter turn or a transpose); an image without EXIF, or already upright, is left alone. Followed by Resize(int, int, ResampleFilter, ColorSpace), Fit(int, int, ResampleFilter, ColorSpace, bool) or Cover(int, int, Anchor, ResampleFilter, ColorSpace), the resize runs first on the stored image and the small result is turned, which matches the other order to within rounding.
public RasterOps AutoOrient()
Returns
- RasterOps
This builder.
AutoThreshold(ThresholdMethod, ThresholdMode, Rgba8?, Rgba8?, bool)
Thresholds at the level method finds in the histogram, as ImageMagick's -auto-threshold; see
FindThreshold(ThresholdMethod, ThresholdMode). Measured like AutoLevel(bool, bool).
public RasterOps AutoThreshold(ThresholdMethod method = ThresholdMethod.Otsu, ThresholdMode mode = ThresholdMode.Luminance, Rgba8? below = null, Rgba8? above = null, bool perFrame = false)
Parameters
methodThresholdMethodHow the level is found. Defaults to Otsu.
modeThresholdModeWhat is measured. Defaults to Luminance.
belowRgba8?The lower color, or null for black.
aboveRgba8?The upper color, or null for white.
perFrameboolWhether each frame is measured alone.
Returns
- RasterOps
This builder.
Examples
// Threshold a scanned page for OCR: Otsu's level for an evenly lit page, or Bradley's local threshold for uneven light.
float level = page.FindThreshold(ThresholdMethod.Otsu);
using Raster<Gray8> even = page.Derive(o => o.AutoThreshold(ThresholdMethod.Otsu), Ct);
using Raster<Gray8> uneven = page.Derive(o => o.AdaptiveThreshold(limit: 0.15f), Ct);
Exceptions
- ArgumentOutOfRangeException
An enum value is not defined.
AutoWhiteBalance(WhiteBalanceMethod, bool)
Removes a color cast it measures, by method. Measured like AutoLevel(bool, bool).
public RasterOps AutoWhiteBalance(WhiteBalanceMethod method = WhiteBalanceMethod.GrayWorld, bool perFrame = false)
Parameters
methodWhiteBalanceMethodHow the cast is found. Defaults to GrayWorld, ImageMagick's -white-balance.
perFrameboolWhether each frame is measured alone.
Returns
- RasterOps
This builder.
Examples
// Correct a tungsten-lit photo, as a raw editor's temperature slider does.
raster.Apply(o => o.WhiteBalance(temperature: 3200), Ct);
// Or pick a gray card's color and make it neutral.
raster.Apply(o => o.WhiteBalance(new Rgba8(182, 170, 151, 255)), Ct);
// Or let the image tell: ImageMagick's gray world, or the brightest pixels as white.
raster.Apply(o => o.AutoWhiteBalance(WhiteBalanceMethod.GrayWorld), Ct);
raster.Apply(o => o.AutoWhiteBalance(WhiteBalanceMethod.WhitePatch), Ct);
Exceptions
- ArgumentOutOfRangeException
methodis not defined.
BilateralBlur(float, float, int?)
Smooths while keeping edges (Tomasi and Manduchi's bilateral filter): each neighbour counts by its distance, through a
Gaussian of spatialSigma, and by how much its color differs, through a Gaussian of
rangeSigma, so noise flattens and edges stay. The color difference is the root-mean-square difference
of red, green and blue on 0..1, so on a gray image the sigmas mean what ImageMagick's -bilateral-blur
WxW+(255·rangeSigma)+spatialSigma means. Alpha is averaged with the same weights; edges repeat the edge pixel.
public RasterOps BilateralBlur(float spatialSigma, float rangeSigma, int? radius = null)
Parameters
spatialSigmafloatThe reach in pixels, above 0 and at most 50.
rangeSigmafloatHow different a color may be and still count, above 0, on the 0..1 scale: 0.1 keeps most edges.
radiusint?The window's radius, or null for ⌈2 · spatialSigma⌉ as ImageMagick's width; at most 100. Above 8 the taps are taken every ⌈radius / 8⌉ pixels, so the cost stays bounded.
Returns
- RasterOps
This builder.
Examples
// Smooth skin or sky while keeping edges: neighbours count less the more their color differs (0.1 on the 0..1 scale).
using Raster smooth = photo.Derive(ops => ops.BilateralBlur(spatialSigma: 4, rangeSigma: 0.1f), Ct);
Exceptions
- ArgumentOutOfRangeException
A sigma is not positive and finite or above its limit, or
radiusis negative or above 100.
BlendColor(Rgba8, BlendMode, float, ColorSpace)
Blends one color over every pixel by mode: Multiply tints, Screen
washes out, Color colorizes. The color's own alpha and opacity set how strongly.
public RasterOps BlendColor(Rgba8 color, BlendMode mode, float opacity = 1, ColorSpace colorSpace = ColorSpace.Encoded)
Parameters
colorRgba8The color, with straight alpha.
modeBlendModeHow the color combines with each pixel.
opacityfloatMultiplies the color's alpha before the mode: 1 uses it as it is.
colorSpaceColorSpaceWhere pixels are blended. Defaults to Encoded.
Returns
- RasterOps
This builder.
Examples
// Warm the photo with an orange tint, and give it a gray-blue color grade.
photo.Apply(ops => ops
.BlendColor(new Rgba8(255, 200, 150, 255), BlendMode.Multiply)
.BlendColor(new Rgba8(60, 80, 110, 255), BlendMode.Color, opacity: 0.3f), Ct);
Exceptions
- ArgumentOutOfRangeException
opacityis outside 0..1, or an enum value is not defined.
Bloom(float, float, float)
Makes bright areas glow, as a camera's bloom: the parts of each channel above threshold, stretched to 0..1
and scaled by intensity, blurred in linear light with Fast and screened onto the
image in linear light. It is exactly the chain written by hand: a layer made with one
ColorMatrix(ColorMatrix) (red, green and blue times k = intensity / (1 − threshold), minus
threshold × k, clamped) and Blur(float, ColorSpace, BlurMethod) in linear light, then
drawn with DrawImage, Screen, in linear light.
public RasterOps Bloom(float threshold = 0.8, float sigma = 10, float intensity = 1)
Parameters
thresholdfloatThe stored value above which a channel blooms, from 0 to under 1.
sigmafloatThe bloom's blur in pixels, from 0 to 1000.
intensityfloatHow strongly the bloom is added, from 0 (nothing) to 100; values are clamped to 1 before the blur.
Returns
- RasterOps
This builder.
Examples
// Highlights above 80% bleed light into their surroundings, added in linear light as a lens does.
photo.Apply(ops => ops.Bloom(threshold: 0.8f, sigma: 12, intensity: 1.5f), Ct);
Exceptions
- ArgumentOutOfRangeException
thresholdis outside 0 to under 1,sigmais outside 0..1000, orintensityis outside 0..100.
Blur(float, ColorSpace)
Blurs with a Gaussian of standard deviation sigma pixels (radius ceil(3σ), weights normalized). Edges
repeat the edge pixel. Above σ = 100, where a true Gaussian needs over 600 taps a pass, it runs as three box blurs of
matched width, whose variance is within 3% of the Gaussian's.
public RasterOps Blur(float sigma, ColorSpace colorSpace = ColorSpace.Encoded)
Parameters
sigmafloatThe standard deviation in pixels; 0 changes nothing.
colorSpaceColorSpaceWhere pixels are blended. Defaults to Encoded.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
sigmais negative or not finite.
Blur(float, ColorSpace, BlurMethod)
Blurs with a Gaussian of standard deviation sigma pixels, computed by method.
Exact is Blur(float, ColorSpace); Fast costs the same at any
σ, for shadows, glows and other large blurs. Edges repeat the edge pixel.
public RasterOps Blur(float sigma, ColorSpace colorSpace, BlurMethod method)
Parameters
sigmafloatThe standard deviation in pixels; 0 changes nothing.
colorSpaceColorSpaceWhere pixels are blended.
methodBlurMethodHow the blur is computed.
Returns
- RasterOps
This builder.
Examples
// A large, soft background blur: Fast costs the same at any sigma and is within 50 dB of the exact Gaussian from sigma 3.
using Raster soft = photo.Derive(ops => ops.Blur(40, ColorSpace.Linear, BlurMethod.Fast), Ct);
Exceptions
- ArgumentOutOfRangeException
sigmais negative, not finite or above 1000, or an enum value is not defined.
BoxBlur(int)
Replaces each pixel with the mean of the (2r + 1) square around it. Edges repeat the edge pixel.
public RasterOps BoxBlur(int radius)
Parameters
radiusintThe radius in pixels; 0 changes nothing.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
radiusis negative or above 1000.
Brightness(float)
Multiplies red, green and blue by amount: 1 changes nothing, 0 gives black. See Brightness(float).
public RasterOps Brightness(float amount)
Parameters
amountfloatThe factor, 0 or more.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
amountis negative or not finite.
CannyEdges(float, float, float)
Finds thin edges with Canny's detector, as ImageMagick's -canny 0x{sigma}+{low × 100}%+{high × 100}% does: the luma is
smoothed by a Gaussian, Canny's first differences give the gradient, pixels that are not the strongest across their edge are
dropped, and hysteresis keeps pixels whose magnitude reaches high times the largest, plus those
8-connected to them that reach low times it. Writes white edges on black, one pixel wide, with alpha
kept: a gray result works as a Mask as it is, a color one with Luminance. Reads the
whole image, so inside a scope it sees all of it.
public RasterOps CannyEdges(float sigma = 1, float low = 0.1, float high = 0.3)
Parameters
sigmafloatThe Gaussian's standard deviation in pixels, 0 (no smoothing) to 100.
lowfloatThe low threshold, as a fraction 0 to 1 of the largest gradient; at most
high.highfloatThe high threshold, as a fraction 0 to 1 of the largest gradient.
Returns
- RasterOps
This builder.
Examples
// Thin white edges on black. A gray raster works as a Mask as it is; an RGBA one needs MaskChannel.Luminance,
// because a Mask of a raster with alpha reads its alpha.
using Raster<Gray8> edges = Raster.Load<Gray8>("duck.png");
edges.Apply(o => o.CannyEdges(sigma: 1.4f).Dilate(1), Ct); // thin edges, thickened
photo.Apply(o => o.Within(new Mask(edges), s => s.FillColor(Rgba8.Red)), Ct); // paint over them
Exceptions
- ArgumentOutOfRangeException
sigmais negative, not finite or above 100; a threshold is outside 0 to 1, orlowis abovehigh.
ChangeSpeed(double)
Plays the animation factor times as fast: every delay is divided by it, rounded to whole milliseconds.
public RasterOps ChangeSpeed(double factor)
Parameters
factordoubleThe speed-up, more than 0: 2 plays twice as fast, 0.5 at half speed.
Returns
- RasterOps
This builder.
Examples
// Twice as fast, then backwards: a boomerang clip is the clip followed by its reverse.
using Raster fast = clip.Derive(ops => ops.ChangeSpeed(2), Ct);
using Raster backwards = fast.Derive(ops => ops.Reverse(), Ct);
Exceptions
- ArgumentOutOfRangeException
factoris not finite or not positive.
ChromaKey(Rgba8, float, float)
Makes pixels whose chroma lies within similarity of color's transparent, keeping their
color: a chroma key for green and blue screens. The distance is taken between Rec. 709 Cb and Cr, leaving luma out, so lighter
and darker patches of an unevenly lit screen stay closer to the key than they do by the RGB distance
MakeTransparent(Rgba8, float, float) uses.
blend ramps alpha back up over the next band of distance, for hair and soft edges. Follow it with
Despill(DespillColor, float, float) to remove the screen's cast from the edges that stay.
public RasterOps ChromaKey(Rgba8 color, float similarity = 0.1, float blend = 0.05)
Parameters
colorRgba8The screen color, such as
#00b140for a green screen; its alpha is ignored.similarityfloatThe chroma distance that becomes fully transparent, from 0 (the key's exact chroma) to 1 (every color), as a share of the largest distance in RGB, the one between green and magenta.
blendfloatThe band of distance beyond
similarityover which alpha returns to full; 0 for a hard edge.
Returns
- RasterOps
This builder.
Examples
// Key out a green screen by chroma, so its lighter and darker patches go too, soften the edge, and take the green cast off
// what is left; then put the result over a new background.
photo.Apply(ops => ops
.ChromaKey(new Rgba8(0, 177, 64, 255), similarity: 0.12f, blend: 0.06f)
.Despill(DespillColor.Green, mix: 0.5f), Ct);
backdrop.Apply(ops => ops.DrawImage(photo, new Point(0, 0)), Ct);
Exceptions
- ArgumentOutOfRangeException
similarityis outside 0..1, orblendis negative or not finite.
Clahe(int, int, float, int)
Contrast-limited adaptive histogram equalization (Zuiderveld, 1994) on L*, as ImageMagick's -clahe: each of
tilesX × tilesY tiles gets its own clipped, equalized curve, blended smoothly between tile
centers, so local detail comes up without the noise of plain equalization. a* and b* are kept. Each frame is its own.
public RasterOps Clahe(int tilesX = 8, int tilesY = 8, float clipLimit = 2, int bins = 256)
Parameters
tilesXintTiles across, from 1 to 256. Defaults to 8.
tilesYintTiles down, from 1 to 256. Defaults to 8.
clipLimitfloatHow far a tile's histogram may rise, as a multiple of its mean bin (2 is mild, 4 strong); 0 does not clip.
binsintThe histogram bins, from 2 to 4,096. Defaults to 256.
Returns
- RasterOps
This builder.
Examples
// Bring out detail in a flat, foggy landscape: CLAHE on 8 × 8 tiles, then ImageMagick's local contrast.
raster.Apply(o => o.Clahe(tilesX: 8, tilesY: 8, clipLimit: 2).LocalContrast(radius: 0.1f, strength: 0.15f), Ct);
Remarks
The lightness plane, 4 bytes a pixel, counts against MaxTotalBytes. Inside a rectangle or mask, the scope is its image.
Exceptions
- ArgumentOutOfRangeException
An argument is out of range.
ColorMatrix(ColorMatrix)
Applies a color matrix to straight RGBA and clamps the result. Adjacent color steps are multiplied into one matrix before anything runs, so the chain clamps once, at its end.
public RasterOps ColorMatrix(ColorMatrix matrix)
Parameters
matrixColorMatrixThe matrix.
Returns
- RasterOps
This builder.
Colorize(Rgba8, float)
Blends red, green and blue toward color, as ImageMagick's -colorize. See Colorize(Rgba8, float).
public RasterOps Colorize(Rgba8 color, float amount)
Parameters
Returns
- RasterOps
This builder.
Examples
// A two-color poster, then a check of how it reads to someone with deuteranopia.
raster.Apply(o => o.Duotone(Rgba8.FromHex("#1b2a49"), Rgba8.FromHex("#f2c14e")).Posterize(4, DitherMode.Ordered), Ct);
using Raster<Rgba8> preview = raster.Derive(o => o.SimulateColorBlindness(ColorVisionDeficiency.Deuteranopia), Ct);
// High contrast for low vision: gray, lightness inverted so dark becomes light, and more contrast.
using Raster<Rgba8> readable = raster.Derive(o => o.HighContrast(grayscale: true, ContrastInvert.Lightness, contrast: 0.3f), Ct);
Exceptions
- ArgumentOutOfRangeException
amountis outside 0..1.
Contrast(float)
Scales red, green and blue around mid-gray: 1 changes nothing, 0 gives flat gray. See Contrast(float).
public RasterOps Contrast(float amount)
Parameters
amountfloatThe factor, 0 or more.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
amountis negative or not finite.
ContrastStretch(float, float, bool, bool)
Clips the darkest black and lightest white fractions of the pixels, then stretches the
rest to 0..1, as ImageMagick's -contrast-stretch. Linked, the points come from the luminance histogram, as ImageMagick's
synced channels. Measured like AutoLevel(bool, bool).
public RasterOps ContrastStretch(float black, float white, bool linked = true, bool perFrame = false)
Parameters
blackfloatThe fraction of pixels that becomes black, from 0 to 1.
whitefloatThe fraction that becomes white, from 0 to 1; with
blackless than 1.linkedboolWhether the channels share one pair of points (the default) or each gets its own.
perFrameboolWhether each frame is measured alone.
Returns
- RasterOps
This builder.
Examples
// Fix a dull scan: stretch it to the full range, clipping the darkest 2% and lightest 1%, then set the midtones.
raster.Apply(o => o.Normalize().AutoGamma(), Ct);
// Or stretch each channel on its own, which also removes a cast.
raster.Apply(o => o.AutoLevel(linked: false), Ct);
// Measured steps measure only their scope: here the sky alone is stretched.
raster.Apply(o => o.Within(new Rect(0, 0, raster.Width, raster.Height / 3), sky => sky.AutoLevel()), Ct);
Exceptions
- ArgumentOutOfRangeException
A fraction is outside 0..1, or the two add up to 1 or more.
ConvertColor(ColorProfile, ColorTransformOptions?)
Converts the pixels from the encoding the raster is in (GetColorProfile(), or the
target of an earlier ConvertColor in the chain) to target, in place, and records the new encoding in the
metadata: no profile for sRGB, the target's ICC profile otherwise. The pixel type stays the same, so the target must have
the pixels' model (an RGB target for gray pixels uses its curve); use ConvertColor<TTo>(ColorProfile, ColorTransformOptions?) to
change model, as from CMYK to RGB.
public RasterOps ConvertColor(ColorProfile target, ColorTransformOptions? options = null)
Parameters
targetColorProfileThe encoding to convert to.
optionsColorTransformOptionsThe intent and black point compensation, or null for the defaults.
Returns
- RasterOps
This builder.
Examples
// What the pixels mean, from the file's ICC profile, tags and gamma; sRGB when it said nothing.
ColorProfile stored = raster.Metadata.GetColorProfile();
// Convert in place to sRGB for the web: the metadata then says sRGB, so no profile is written.
raster.Apply(ops => ops.ConvertColor(ColorProfile.Srgb));
Exceptions
- ArgumentNullException
targetis null.
Convolve(ConvolutionKernel, EdgeMode, bool)
Convolves with a kernel, applied as laid out. Color and alpha are filtered together in premultiplied form unless
preserveAlpha is set, which filters only the color and keeps each pixel's alpha, as edge-detect kernels need.
public RasterOps Convolve(ConvolutionKernel kernel, EdgeMode edge = EdgeMode.Clamp, bool preserveAlpha = false)
Parameters
kernelConvolutionKernelThe kernel. Separable kernels run as two 1D passes.
edgeEdgeModeHow taps past the border are read. Defaults to Clamp.
preserveAlphaboolWhether to keep the source alpha and filter only red, green and blue.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
edgeis not defined.- ArgumentNullException
kernelis null.
CopyAlpha(Mask)
Sets alpha to mask's coverage and keeps the color: a gray image from elsewhere becomes the transparency.
Outside the mask raster coverage is 0, so pixels there become transparent, unless the mask is inverted.
public RasterOps CopyAlpha(Mask mask)
Parameters
maskMaskThe coverage: a raster of any size and type, placed at its offset, read by its channel.
Returns
- RasterOps
This builder.
Examples
using Raster alpha = photo.Derive(ops => ops.AlphaToGray(), Ct); // see the transparency as gray
using Raster cutout = photo.Derive(ops => ops.CopyAlpha(new Mask(matte)), Ct); // a gray image becomes the alpha
using Raster onWhite = cutout.Derive(ops => ops.Flatten(Rgba8.White), Ct); // composite onto white, opaque
using Raster luma = photo.Derive(ops => ops.LuminanceToAlpha(), Ct); // brightness becomes alpha
Remarks
The mask raster must stay undisposed until the chain has run. Copying a raster's own coverage reads from a copy.
Exceptions
- ArgumentException
The mask has no raster.
- ArgumentOutOfRangeException
The mask's channel is not defined.
Cover(int, int, Anchor, ResampleFilter, ColorSpace)
Scales the image to cover width × height with its aspect ratio kept, keeping the part at
anchor. Only the kept part is read; nothing is cropped first.
public RasterOps Cover(int width, int height, Anchor anchor = Anchor.Center, ResampleFilter filter = ResampleFilter.Bicubic, ColorSpace colorSpace = ColorSpace.Encoded)
Parameters
widthintThe output width, at least 1.
heightintThe output height, at least 1.
anchorAnchorWhich part of the image to keep. Defaults to the center.
filterResampleFilterThe resampling kernel. Defaults to Bicubic.
colorSpaceColorSpaceWhere pixels are blended. Defaults to Encoded.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
A size is less than 1, or an enum value is not defined.
Crop(Rect)
Keeps one rectangle of the image. The pixels are copied exactly.
public RasterOps Crop(Rect rect)
Parameters
rectRectThe rectangle to keep. It must lie inside the image, which is checked before any pixel changes.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
The rectangle is empty, or leaves the image when the chain runs.
Crop(int, int, int, int)
Keeps one rectangle of the image. The pixels are copied exactly.
public RasterOps Crop(int x, int y, int width, int height)
Parameters
xintThe left edge of the rectangle.
yintThe top edge of the rectangle.
widthintThe width of the rectangle, at least 1.
heightintThe height of the rectangle, at least 1.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
The rectangle is empty, or leaves the image when the chain runs.
Deskew(float, Rgba8?, bool, ResampleFilter)
Straightens a scanned or photographed page: detects the tilt of its text lines (see DetectSkew(float)) and turns the image back by it. Every frame is turned by the first frame's angle; an image with no clear lines is left as it is.
public RasterOps Deskew(float maxAngle = 15, Rgba8? background = null, bool keepSize = true, ResampleFilter filter = ResampleFilter.Bicubic)
Parameters
maxAnglefloatThe largest tilt looked for, in degrees, more than 0 and at most 45.
backgroundRgba8?The color of the uncovered corners, or null (the default) for the top-left pixel's, the border color Trim would use.
keepSizeboolWhether the page keeps its size (the default, as a scanner user expects), or the canvas grows to the turned bounds as Rotate does.
filterResampleFilterThe resampling kernel for the turn.
Returns
- RasterOps
This builder.
Examples
// Measure the tilt first, if you want to show it or decide yourself...
float tilt = photo.DetectSkew(maxAngle: 10);
// ...or straighten in one step, keeping the page size with white corners.
using Raster straight = photo.Derive(ops => ops.Deskew(background: Rgba8.White), Ct);
Remarks
The angle depends on the pixels, so the chain runs up to the deskew and measures; it cannot run inside Within.
Exceptions
- ArgumentOutOfRangeException
maxAngleis out of range, orfilteris not defined.
Despeckle()
Removes specks while keeping edges, by Crimmins' complementary hulling exactly as ImageMagick's -despeckle runs it: each color channel is nudged, a level at a time, toward neighbours that differ by two levels or more, in 16 passes along four directions. Alpha is kept. The image's border is compared with black, as ImageMagick does.
public RasterOps Despeckle()
Returns
- RasterOps
This builder.
Examples
// Clean a scan: specks shrink, edges and text stay. Median(1) is the stronger alternative.
scan.Apply(ops => ops.Despeckle(), Ct);
Despill(DespillColor, float, float)
Removes the colored cast a green or blue screen leaves on edges, hair and see-through pixels: the screen's channel is held down to a limit taken from the other two channels. Run it after ChromaKey(Rgba8, float, float) or MakeTransparent(Rgba8, float, float), or on its own on a photo shot in front of a screen.
public RasterOps Despill(DespillColor screen = DespillColor.Green, float mix = 0.5, float expand = 0)
Parameters
screenDespillColorThe screen color whose spill is removed.
mixfloatHow the limit is taken from the other two channels, from 0 (their average, the strongest removal) to 1 (the larger of the two, the gentlest, which leaves neutral colors alone).
expandfloatHow much further the limit is lowered, from 0 to 1, for heavy spill; this darkens the screen's channel more.
Returns
- RasterOps
This builder.
Examples
// Key out a green screen by chroma, so its lighter and darker patches go too, soften the edge, and take the green cast off
// what is left; then put the result over a new background.
photo.Apply(ops => ops
.ChromaKey(new Rgba8(0, 177, 64, 255), similarity: 0.12f, blend: 0.06f)
.Despill(DespillColor.Green, mix: 0.5f), Ct);
backdrop.Apply(ops => ops.DrawImage(photo, new Point(0, 0)), Ct);
Exceptions
- ArgumentOutOfRangeException
screenis not defined, ormixorexpandis outside 0..1.
Dilate(int)
The maximum over the (2r + 1) square around each pixel: light areas grow by radius pixels.
public RasterOps Dilate(int radius)
Parameters
radiusintThe radius in pixels, 0 (changes nothing) to 1000.
Returns
- RasterOps
This builder.
Examples
using Raster grown = photo.Derive(o => o.Dilate(3), Ct); // light areas grow 3 px: a 7 × 7 square
using Raster shrunk = photo.Derive(o => o.Erode(3), Ct); // light areas shrink 3 px
using Raster wide = photo.Derive(o => o.Dilate(6, 1), Ct); // 13 × 3, as Skia's dilate radii
Exceptions
- ArgumentOutOfRangeException
radiusis negative or above 1000.
Dilate(int, int)
The maximum over the (2rx + 1) × (2ry + 1) rectangle around each pixel, as Skia's dilate filter with those radii.
public RasterOps Dilate(int radiusX, int radiusY)
Parameters
radiusXintThe horizontal radius in pixels, 0 to 1000.
radiusYintThe vertical radius in pixels, 0 to 1000.
Returns
- RasterOps
This builder.
Examples
using Raster grown = photo.Derive(o => o.Dilate(3), Ct); // light areas grow 3 px: a 7 × 7 square
using Raster shrunk = photo.Derive(o => o.Erode(3), Ct); // light areas shrink 3 px
using Raster wide = photo.Derive(o => o.Dilate(6, 1), Ct); // 13 × 3, as Skia's dilate radii
Exceptions
- ArgumentOutOfRangeException
A radius is negative or above 1000.
Displace(Raster, float, float, ColorChannel, ColorChannel, SamplingOptions?)
Moves each pixel by a displacement map, as Skia's DisplacementMap and ImageMagick's -displace do: pixel (x, y) shows the source at (x + scaleX × (mx − 0.5), y + scaleY × (my − 0.5)), with mx and my the map's chosen channels from 0 to 1, so mid-gray moves nothing. The map's first frame serves every frame.
public RasterOps Displace(Raster map, float scaleX, float scaleY, ColorChannel xChannel = ColorChannel.Red, ColorChannel yChannel = ColorChannel.Green, SamplingOptions? options = null)
Parameters
mapRasterThe displacement map, the image's size (Resize it first if it is not).
scaleXfloatThe horizontal move, in pixels, for a channel going from 0 to 1.
scaleYfloatThe vertical move, in pixels, for a channel going from 0 to 1.
xChannelColorChannelThe map channel that moves pixels horizontally.
yChannelColorChannelThe map channel that moves pixels vertically.
optionsSamplingOptionsThe filter, color space, edges and background, or null for the defaults.
Returns
- RasterOps
This builder.
Examples
// A displacement map the image's size: mid-gray moves nothing, red moves pixels sideways and green up and down.
using Raster<Rgba8> map = Raster.Create<Rgba8>(photo.Width, photo.Height);
map.ForEachRow((row, y) =>
{
for (int x = 0; x < row.Length; x++)
{
byte wave = (byte)(128 + (100 * Math.Sin((x + y) / 12.0)));
row[x] = new Rgba8(wave, 128, 128, 255);
}
});
using Raster<Rgba8> rippled = photo.Derive(ops => ops.Displace(map, 16, 0), Ct);
Exceptions
- ArgumentNullException
mapis null.- ArgumentOutOfRangeException
A scale is not finite or a channel is not defined.
- ArgumentException
The map's size differs from the image's, when the chain is planned.
DrawAnimation(Raster, Point, AnimationOverlayOptions?)
Draws an animation (or a still) onto this one at position. By time (the default) both timelines are cut
at every frame boundary of either, so an overlay at another speed keeps its speed; each piece shows the base frame and the
overlay frame of that moment, drawn as DrawImage does with the blend mode and opacity. The overlay loops for as long as the
base runs unless Repeat says otherwise; a still base lasts as long as the overlay
plays and takes its loop count. The overlay is converted to this raster's pixel type. The output frame count is checked
against MaxFrames and MaxTotalBytes before anything is drawn.
public RasterOps DrawAnimation(Raster overlay, Point position, AnimationOverlayOptions? options = null)
Parameters
overlayRasterThe animation or still to draw.
positionPointWhere its top-left corner goes; it may lie partly or wholly outside.
optionsAnimationOverlayOptionsThe blending, repeat count, start and timing, or null for Default.
Returns
- RasterOps
This builder.
Examples
// A looping sticker on an animated background: the sticker keeps its own speed and loops for the background's whole length.
background.Apply(ops => ops.DrawAnimation(sticker, new Point(10, 10), new AnimationOverlayOptions { Repeat = 0, Opacity = 0.9f }), Ct);
background.Save("with-sticker.gif");
Exceptions
- ArgumentNullException
overlayis null.- LimitExceededException
The result would break MaxFrames or MaxTotalBytes.
DrawArithmetic(Raster, Point, float, float, float, float, bool)
Draws image with the arithmetic composite (SVG's feComposite arithmetic operator, Skia's arithmetic blender):
each channel of the premultiplied result is k1·S·D + k2·S + k3·D + k4, with S the image and D this raster, in 0..1. Only the
overlap changes. k2 = k3 = 0.5 averages the two; k1 = 1 multiplies them.
public RasterOps DrawArithmetic(Raster image, Point position, float k1, float k2, float k3, float k4, bool clamp = true)
Parameters
imageRasterThe image to draw. It must stay undisposed until the chain has run; its first frame is drawn onto every frame.
positionPointWhere its top-left corner goes; may be negative.
k1floatThe weight of the product S·D.
k2floatThe weight of S.
k3floatThe weight of D.
k4floatThe constant added.
clampboolWhether each result is kept a valid premultiplied pixel: every channel in 0..1 and color no higher than alpha. Without it, only the pixel type's own range applies.
Returns
- RasterOps
This builder.
Examples
// Average two images: each channel becomes 0.5·S + 0.5·D.
photo.Apply(ops => ops.DrawArithmetic(other, new Point(0, 0), k1: 0, k2: 0.5f, k3: 0.5f, k4: 0), Ct);
Exceptions
- ArgumentOutOfRangeException
A weight is not finite.
- ArgumentNullException
imageis null.
DrawImage(Raster, Point, BlendMode, float, ColorSpace)
Draws image onto this raster with its top-left corner at position, combining each pixel
with the one under it by mode. Only the overlap of the image and this raster changes, as when drawing a
layer: SourceIn and DestinationIn do not clear what lies outside the image.
SourceOver on stored values gives exactly what DrawImage(Raster, Point, float) gives.
public RasterOps DrawImage(Raster image, Point position, BlendMode mode, float opacity = 1, ColorSpace colorSpace = ColorSpace.Encoded)
Parameters
imageRasterThe image to draw, of any pixel type. It must stay undisposed until the chain has run; its first frame is drawn onto every frame.
positionPointWhere its top-left corner goes; may be negative.
modeBlendModeHow each pixel combines with the one under it.
opacityfloatMultiplies the image's alpha before the mode: 1 draws it as it is.
colorSpaceColorSpaceWhere pixels are blended. Defaults to Encoded, as browsers and editors blend.
Returns
- RasterOps
This builder.
Examples
// Print the photo onto paper: Multiply keeps the paper's texture under every color.
paper.Apply(ops => ops.DrawImage(photo, new Point(0, 0), BlendMode.Multiply), Ct);
// Or lighten it in linear light at half strength; only where the photo overlaps changes.
paper.Apply(ops => ops.DrawImage(photo, new Point(10, 10), BlendMode.Screen, 0.5f, ColorSpace.Linear), Ct);
Exceptions
- ArgumentOutOfRangeException
opacityis outside 0..1, or an enum value is not defined.- ArgumentNullException
imageis null.
DrawImage(Raster, Point, float)
Draws image onto this raster with its top-left corner at position, using source-over
blending (the normal way a layer covers what is under it). The image may sit partly or wholly outside; only the overlap
changes. Its first frame is drawn onto every frame, and it may be any pixel type.
public RasterOps DrawImage(Raster image, Point position, float opacity = 1)
Parameters
imageRasterThe image to draw. It must stay undisposed until the chain has run.
positionPointWhere its top-left corner goes; may be negative.
opacityfloatMultiplies the image's alpha: 1 draws it as it is, 0 draws nothing.
Returns
- RasterOps
This builder.
Remarks
Drawing a raster onto itself reads from a copy of it, made when the step runs.
Exceptions
- ArgumentOutOfRangeException
opacityis outside 0..1.- ArgumentNullException
imageis null.
DrawImage(Raster, Rect, Point, BlendMode, float, ColorSpace)
Draws the part of image inside sourceArea onto this raster with that part's top-left
corner at position, combining pixels by mode as
DrawImage(Raster, Point, BlendMode, float, ColorSpace) does for the whole image.
public RasterOps DrawImage(Raster image, Rect sourceArea, Point position, BlendMode mode, float opacity = 1, ColorSpace colorSpace = ColorSpace.Encoded)
Parameters
imageRasterThe image to draw from. It must stay undisposed until the chain has run.
sourceAreaRectThe part of the image to draw, clipped to the image.
positionPointWhere the area's top-left corner goes; may be negative.
modeBlendModeHow each pixel combines with the one under it.
opacityfloatMultiplies the image's alpha before the mode: 1 draws it as it is.
colorSpaceColorSpaceWhere pixels are blended. Defaults to Encoded.
Returns
- RasterOps
This builder.
Examples
// Print the photo onto paper: Multiply keeps the paper's texture under every color.
paper.Apply(ops => ops.DrawImage(photo, new Point(0, 0), BlendMode.Multiply), Ct);
// Or lighten it in linear light at half strength; only where the photo overlaps changes.
paper.Apply(ops => ops.DrawImage(photo, new Point(10, 10), BlendMode.Screen, 0.5f, ColorSpace.Linear), Ct);
Exceptions
- ArgumentOutOfRangeException
sourceAreadoes not overlap the image,opacityis outside 0..1, or an enum value is not defined.- ArgumentNullException
imageis null.
DrawImage(Raster, Rect, Point, float)
Draws the part of image inside sourceArea onto this raster with that part's top-left
corner at position, as DrawImage(Raster, Point, float) does for the whole image. Use it for
sprite sheets, tiles and partial updates: no copy of the area is made.
public RasterOps DrawImage(Raster image, Rect sourceArea, Point position, float opacity = 1)
Parameters
imageRasterThe image to draw from. It must stay undisposed until the chain has run.
sourceAreaRectThe part of the image to draw, clipped to the image.
positionPointWhere the area's top-left corner goes; may be negative.
opacityfloatMultiplies the image's alpha: 1 draws it as it is, 0 draws nothing.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
sourceAreadoes not overlap the image, oropacityis outside 0..1.- ArgumentNullException
imageis null.
DropShadow(float, float, float, Rgba8, DropShadowOptions?)
Adds a drop shadow, as Skia's DropShadow image filter: the image's alpha, moved by (dx,
dy), blurred by a Gaussian of sigma and filled with color, with the
image drawn over it source-over. By default the canvas grows by 3σ plus the offset on the sides the shadow reaches past the
image, so it is never cut off, and the step then cannot run inside Within(Rect, Action<RasterOps>); set
Expand to false to keep the size. The shadow fades as if the image went on,
transparent, past its edges.
public RasterOps DropShadow(float dx, float dy, float sigma, Rgba8 color, DropShadowOptions? options = null)
Parameters
dxfloatHow far the shadow moves right, in pixels (negative moves it left), at most 10000 either way.
dyfloatHow far the shadow moves down, in pixels, at most 10000 either way.
sigmafloatThe shadow's blur in pixels, from 0 (a hard shadow) to 1000.
colorRgba8The shadow's color, with its alpha as the shadow's opacity.
optionsDropShadowOptionsA separate vertical blur, whether the canvas grows, whether only the shadow is kept, and the blur method; the defaults when null.
Returns
- RasterOps
This builder.
Examples
// Skia's DropShadow: 6 px right and down, blurred with sigma 8, black at 55%; the canvas grows to hold the shadow.
using Raster shadowed = logo.Derive(ops => ops.DropShadow(6, 6, 8, new Rgba8(0, 0, 0, 140)), Ct);
// Keep the size, or keep only the shadow (as Skia's DropShadowOnly and ImageMagick's -shadow).
using Raster same = logo.Derive(ops => ops.DropShadow(4, 4, 3, Rgba8.Black, new DropShadowOptions { Expand = false }), Ct);
using Raster shadow = logo.Derive(ops => ops.DropShadow(0, 10, 12, Rgba8.Black, new DropShadowOptions { ShadowOnly = true, SigmaY = 6 }), Ct);
Exceptions
- ArgumentOutOfRangeException
An offset is not finite or beyond 10000 either way, or
sigmais outside 0..1000.
DropZeroDelay()
Removes frames with no delay, which no viewer shows, as ImageMagick's -layers RemoveZero; when every frame has none, nothing is removed.
public RasterOps DropZeroDelay()
Returns
- RasterOps
This builder.
Examples
// Shrink a screen recording: merge frames that barely change, drop frames no viewer shows, then resample to 25 fps.
recording.Apply(ops => ops.MergeDuplicates(tolerance: 0.01f).DropZeroDelay().Retime(25), Ct);
recording.Save("recording.gif");
Duotone(Rgba8, Rgba8, LumaWeights)
Maps luminance onto the line from shadows to highlights. See Duotone(Rgba8, Rgba8, LumaWeights).
public RasterOps Duotone(Rgba8 shadows, Rgba8 highlights, LumaWeights weights = LumaWeights.Rec709)
Parameters
shadowsRgba8The color for black.
highlightsRgba8The color for white.
weightsLumaWeightsThe luma weights. Defaults to Rec709.
Returns
- RasterOps
This builder.
Examples
// A two-color poster, then a check of how it reads to someone with deuteranopia.
raster.Apply(o => o.Duotone(Rgba8.FromHex("#1b2a49"), Rgba8.FromHex("#f2c14e")).Posterize(4, DitherMode.Ordered), Ct);
using Raster<Rgba8> preview = raster.Derive(o => o.SimulateColorBlindness(ColorVisionDeficiency.Deuteranopia), Ct);
// High contrast for low vision: gray, lightness inverted so dark becomes light, and more contrast.
using Raster<Rgba8> readable = raster.Derive(o => o.HighContrast(grayscale: true, ContrastInvert.Lightness, contrast: 0.3f), Ct);
Exceptions
- ArgumentOutOfRangeException
weightsis not defined.
Edges(EdgeOperator, bool)
Replaces each pixel with the strength of the edge through it: the gradient magnitude of op's kernels, scaled
so a full black-to-white step gives 1, clamped to 0 to 1. Computed on premultiplied values with edges repeating the edge
pixel; alpha is kept. In gray mode the pixels are first reduced to Rec. 709 luma and the magnitude is written as gray;
otherwise each color channel gets its own.
public RasterOps Edges(EdgeOperator op = EdgeOperator.Sobel, bool grayscale = true)
Parameters
opEdgeOperatorThe kernels; Sobel by default.
grayscaleboolWhether to find edges in the luma (gray result) rather than per channel.
Returns
- RasterOps
This builder.
Examples
using Raster edges = photo.Derive(o => o.Edges(), Ct); // Sobel, gray, 0 to 1
using Raster crisp = photo.Derive(o => o.Edges(EdgeOperator.Scharr), Ct); // rotation-steady
using Raster colored = photo.Derive(o => o.Edges(EdgeOperator.Sobel, grayscale: false), Ct); // per channel
using Raster lines = photo.Derive(o => o.Blur(1).Edges(EdgeOperator.Laplacian3x3), Ct); // second derivative
Exceptions
- ArgumentOutOfRangeException
opis not defined.
Emboss(float, float, float, bool)
Embosses: blurs with a Gaussian of sigma, takes the slope toward the light at angle
with a 3 × 3 Sobel stencil, scales it by depth and adds mid gray, so flat areas become 0.5 and slopes
facing the light are lighter. This is the classic directional emboss; ImageMagick's -emboss is a different filter (a
diagonal sharpening kernel followed by histogram equalization). Works on stored values; alpha is kept; edges repeat the
edge pixel.
public RasterOps Emboss(float angle = 135, float depth = 1, float sigma = 1, bool grayscale = true)
Parameters
anglefloatWhere the light comes from, in degrees counterclockwise from the right with y up, as -shade's azimuth; 135 is the top left.
depthfloatThe strength of the relief, from 0 (flat gray) to 100; 1 maps a slope of one level per pixel to one level.
sigmafloatThe blur before the slope is taken, in pixels, from 0 (none) to 100.
grayscaleboolWhether the height is the Rec. 709 luminance and the result gray; otherwise each color channel is embossed on its own.
Returns
- RasterOps
This builder.
Examples
// Gray relief: flat paper becomes mid gray, strokes rise toward the light at the top left.
using Raster embossed = page.Derive(ops => ops.Emboss(angle: 135, depth: 3, sigma: 1), Ct);
// Each color channel on its own, softer and deeper.
using Raster colored = page.Derive(ops => ops.Emboss(angle: 45, depth: 6, sigma: 2, grayscale: false), Ct);
Exceptions
- ArgumentOutOfRangeException
angleis not finite, ordepthorsigmais out of range.
EntropyCrop(float)
Crops to the busiest part of the image: the bounding box of the 16 × 16 tiles whose luminance entropy (the Shannon entropy
of the tile's 256-level histogram, over 8 bits) reaches threshold.
Frames are cropped to the union of their boxes; an image with no busy tile is left as it is.
public RasterOps EntropyCrop(float threshold = 0.5)
Parameters
thresholdfloatThe entropy a tile needs, from 0 (every tile) to 1 (only uniformly random noise).
Returns
- RasterOps
This builder.
Examples
// Keep the part with detail in it: flat tiles (a plain backdrop) fall away.
Rect busy = padded.EntropyBounds();
using Raster<Rgba8> cropped = padded.Derive(ops => ops.EntropyCrop(), Ct);
Remarks
Like Trim(float, Rgba8?), the size depends on the pixels, so it cannot run inside Within.
Exceptions
- ArgumentOutOfRangeException
thresholdis outside 0..1.
Equalize(EqualizeMode, bool)
Spreads the values evenly by histogram equalization: of L* by default, keeping a* and b* so colors hold, or of each channel as ImageMagick's -equalize. Measured like AutoLevel(bool, bool); a flat image is left alone.
public RasterOps Equalize(EqualizeMode mode = EqualizeMode.Luminance, bool perFrame = false)
Parameters
modeEqualizeModeWhat is equalized. Defaults to Luminance.
perFrameboolWhether each frame is measured alone.
Returns
- RasterOps
This builder.
Examples
// Spread the lightness evenly without shifting colors, or each channel on its own as ImageMagick's -equalize.
using Raster<Rgba8> even = raster.Derive(o => o.Equalize(EqualizeMode.Luminance), Ct);
using Raster<Rgba8> strong = raster.Derive(o => o.Equalize(EqualizeMode.Channels), Ct);
Exceptions
- ArgumentOutOfRangeException
modeis not defined.
Erode(int)
The minimum over the (2r + 1) square around each pixel: light areas shrink by radius pixels.
public RasterOps Erode(int radius)
Parameters
radiusintThe radius in pixels, 0 (changes nothing) to 1000.
Returns
- RasterOps
This builder.
Examples
using Raster grown = photo.Derive(o => o.Dilate(3), Ct); // light areas grow 3 px: a 7 × 7 square
using Raster shrunk = photo.Derive(o => o.Erode(3), Ct); // light areas shrink 3 px
using Raster wide = photo.Derive(o => o.Dilate(6, 1), Ct); // 13 × 3, as Skia's dilate radii
Exceptions
- ArgumentOutOfRangeException
radiusis negative or above 1000.
Erode(int, int)
The minimum over the (2rx + 1) × (2ry + 1) rectangle around each pixel, as Skia's erode filter with those radii.
public RasterOps Erode(int radiusX, int radiusY)
Parameters
radiusXintThe horizontal radius in pixels, 0 to 1000.
radiusYintThe vertical radius in pixels, 0 to 1000.
Returns
- RasterOps
This builder.
Examples
using Raster grown = photo.Derive(o => o.Dilate(3), Ct); // light areas grow 3 px: a 7 × 7 square
using Raster shrunk = photo.Derive(o => o.Erode(3), Ct); // light areas shrink 3 px
using Raster wide = photo.Derive(o => o.Dilate(6, 1), Ct); // 13 × 3, as Skia's dilate radii
Exceptions
- ArgumentOutOfRangeException
A radius is negative or above 1000.
FillColor(Rgba8, Rect?)
Sets every pixel in rect, or the whole image, to one color. Alpha is replaced, not blended.
public RasterOps FillColor(Rgba8 color, Rect? rect = null)
Parameters
colorRgba8The color.
rectRect?The area to fill, which must lie inside the image, or null for the whole image.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
The rectangle is empty, or leaves the image when the chain runs.
Fit(int, int, ResampleFilter, ColorSpace, bool)
Scales the image to fit inside width × height with its aspect ratio kept, so one side
matches the box and the other is no larger.
public RasterOps Fit(int width, int height, ResampleFilter filter = ResampleFilter.Bicubic, ColorSpace colorSpace = ColorSpace.Encoded, bool enlarge = true)
Parameters
widthintThe width of the box, at least 1.
heightintThe height of the box, at least 1.
filterResampleFilterThe resampling kernel. Defaults to Bicubic.
colorSpaceColorSpaceWhere pixels are blended. Defaults to Encoded.
enlargeboolWhether an image smaller than the box is enlarged. Pass false for thumbnails.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
A size is less than 1.
Flatten(Rgba8, ColorSpace)
Composites the image over background and makes it opaque, as ImageMagick's -alpha remove
does. The background's own alpha is ignored. Saving a JPEG with a Background option uses the same arithmetic.
public RasterOps Flatten(Rgba8 background, ColorSpace colorSpace = ColorSpace.Encoded)
Parameters
backgroundRgba8The color to show through transparent pixels.
colorSpaceColorSpaceWhere pixels are blended. Defaults to Encoded.
Returns
- RasterOps
This builder.
Examples
using Raster alpha = photo.Derive(ops => ops.AlphaToGray(), Ct); // see the transparency as gray
using Raster cutout = photo.Derive(ops => ops.CopyAlpha(new Mask(matte)), Ct); // a gray image becomes the alpha
using Raster onWhite = cutout.Derive(ops => ops.Flatten(Rgba8.White), Ct); // composite onto white, opaque
using Raster luma = photo.Derive(ops => ops.LuminanceToAlpha(), Ct); // brightness becomes alpha
Exceptions
- ArgumentOutOfRangeException
colorSpaceis not defined.
FlipHorizontal()
Mirrors the image left to right. The pixels are moved exactly.
public RasterOps FlipHorizontal()
Returns
- RasterOps
This builder.
FlipVertical()
Mirrors the image top to bottom. The pixels are moved exactly. Both flips together equal rotating by 180°.
public RasterOps FlipVertical()
Returns
- RasterOps
This builder.
FloodFill(Point, Rgba8, float, Connectivity)
Fills the region connected to seed whose colors lie within tolerance of the seed's own with
fill, as ImageMagick's -fuzz with -floodfill does. Each frame is filled from the same seed.
public RasterOps FloodFill(Point seed, Rgba8 fill, float tolerance = 0, Connectivity connectivity = Connectivity.Four)
Parameters
seedPointWhere the fill starts. It must lie inside the image, which is checked before any pixel changes.
fillRgba8The color to fill with.
tolerancefloatThe color distance, from 0 (the seed's exact color) to 1 (every color).
connectivityConnectivityWhether the fill spreads to the four side neighbours (the default) or also the diagonal ones.
Returns
- RasterOps
This builder.
Examples
// Fill the region around (10, 10) whose colors are close to its own, as a paint bucket does.
photo.Apply(ops => ops.FloodFill(new Point(10, 10), Rgba8.White, tolerance: 0.1f), Ct);
Remarks
The fill keeps a visited set of one bit a pixel, which counts against MaxTotalBytes.
Exceptions
- ArgumentOutOfRangeException
toleranceis outside 0..1,connectivityis not defined, or the seed lies outside the image when the chain runs.
Gamma(float)
Raises red, green and blue to 1/gamma, as ImageMagick's -gamma: 2.2 brightens. See Gamma(float).
public RasterOps Gamma(float gamma)
Parameters
gammafloatThe gamma, above 0.
Returns
- RasterOps
This builder.
Examples
// A basic tone panel: levels with a midtone lift, a gentle S-curve, and a warm tint in the midtones. The three steps run as
// one pass over the pixels.
raster.Apply(o => o
.Level(black: 0.04f, white: 0.96f, gamma: 1.1f)
.SigmoidalContrast(4, midpoint: 0.5f)
.Tint(new Rgba8(255, 200, 150, 255), 0.15f), Ct);
raster.Save("duck-toned.jpg");
Exceptions
- ArgumentOutOfRangeException
gammais not a positive finite number.
Glow(float, Rgba8, float, bool)
Adds a glow around the image's alpha shape, as an editor's outer glow layer style: the alpha, blurred with
Fast, spread, and filled with color, drawn behind the image. With
inner the glow comes in from the shape's edges instead and is drawn on the image, inside the shape only.
It is exactly the chain written by hand: a layer made with a ColorMatrix(ColorMatrix) (the color, and
alpha or 1 − alpha), Blur(float, ColorSpace, BlurMethod), Arithmetic(PixelMath, float, ColorChannels) multiplying alpha by
1 / (1 − spread) and Opacity(float) for the color's alpha, then drawn with DrawImage (the image over the layer, or
the layer over the image with SourceAtop). An opaque image has no edge to glow from.
public RasterOps Glow(float sigma, Rgba8 color, float spread = 0, bool inner = false)
Parameters
sigmafloatThe glow's blur in pixels, from 0 to 1000.
colorRgba8The glow's color, with its alpha as the glow's opacity.
spreadfloatHow much the glow is hardened before it fades, from 0 (a plain blur) to just under 1 (a hard edge): the blurred alpha is divided by 1 − spread.
innerboolWhether the glow is inside the shape instead of around it.
Returns
- RasterOps
This builder.
Examples
// A soft yellow glow around the badge, behind it; spread hardens it before it fades.
using Raster outer = logo.Derive(ops => ops.Glow(8, new Rgba8(255, 210, 0, 230), spread: 0.3f), Ct);
// A white glow coming in from the badge's edges, inside it only.
using Raster inner = logo.Derive(ops => ops.Glow(5, Rgba8.White, inner: true), Ct);
Exceptions
- ArgumentOutOfRangeException
sigmais outside 0..1000, orspreadis outside 0 to under 1.
Grayscale(LumaWeights, float, ColorSpace)
Converts toward gray. By default the luma is taken from the stored, gamma-encoded values, as CSS filters do; pass Linear to weigh the colors in linear light, which keeps perceived brightness better.
public RasterOps Grayscale(LumaWeights mode = LumaWeights.Rec709, float amount = 1, ColorSpace colorSpace = ColorSpace.Encoded)
Parameters
modeLumaWeightsThe luma weights. Defaults to Rec709.
amountfloat0 changes nothing, 1 gives full gray.
colorSpaceColorSpaceWhere the luma is taken. Defaults to Encoded.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
An argument is out of range.
HighContrast(bool, ContrastInvert, float)
Skia's high-contrast accessibility filter. See HighContrast(bool, ContrastInvert, float).
public RasterOps HighContrast(bool grayscale = false, ContrastInvert invert = ContrastInvert.None, float contrast = 0)
Parameters
grayscaleboolWhether colors become gray first.
invertContrastInvertHow to invert. Defaults to None.
contrastfloatThe contrast, from −1 to 1.
Returns
- RasterOps
This builder.
Examples
// A two-color poster, then a check of how it reads to someone with deuteranopia.
raster.Apply(o => o.Duotone(Rgba8.FromHex("#1b2a49"), Rgba8.FromHex("#f2c14e")).Posterize(4, DitherMode.Ordered), Ct);
using Raster<Rgba8> preview = raster.Derive(o => o.SimulateColorBlindness(ColorVisionDeficiency.Deuteranopia), Ct);
// High contrast for low vision: gray, lightness inverted so dark becomes light, and more contrast.
using Raster<Rgba8> readable = raster.Derive(o => o.HighContrast(grayscale: true, ContrastInvert.Lightness, contrast: 0.3f), Ct);
Exceptions
- ArgumentOutOfRangeException
An argument is out of range.
HueRotate(float)
Rotates hue around the luma axis. See HueRotate(float).
public RasterOps HueRotate(float degrees)
Parameters
degreesfloatThe angle; 0 changes nothing.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
degreesis not finite.
InnerShadow(float, float, float, Rgba8)
Adds a shadow inside the image's alpha shape, as an editor's inner shadow layer style: everything outside the shape, moved
by (dx, dy) rounded to whole pixels, blurred with Fast and
filled with color, drawn on the image inside the shape only. Past the image's edges counts as outside, so
a shape that touches an edge is shadowed from there too. It is exactly the chain written by hand: a layer made with a
ColorMatrix(ColorMatrix) (the color, and 1 − alpha), Offset(int, int, EdgeMode, Rgba8) with the uncovered strips
filled with the opaque color, Blur(float, ColorSpace, BlurMethod) and Opacity(float) for the color's
alpha, then drawn over the image with SourceAtop.
public RasterOps InnerShadow(float dx, float dy, float sigma, Rgba8 color)
Parameters
dxfloatHow far the shadow moves right, in pixels (negative moves it left), at most 10000 either way.
dyfloatHow far the shadow moves down, in pixels, at most 10000 either way.
sigmafloatThe shadow's blur in pixels, from 0 (a hard shadow) to 1000.
colorRgba8The shadow's color, with its alpha as the shadow's opacity.
Returns
- RasterOps
This builder.
Examples
// A shadow inside the badge, cast from up and left, as a pressed button looks.
using Raster pressed = logo.Derive(ops => ops.InnerShadow(2, 3, 3, new Rgba8(0, 0, 0, 140)), Ct);
Exceptions
- ArgumentOutOfRangeException
An offset is not finite or beyond 10000 either way, or
sigmais outside 0..1000.
Invert(float)
Replaces red, green and blue with 1 − value, blended by amount. See Invert(float).
public RasterOps Invert(float amount = 1)
Parameters
amountfloat0 changes nothing, 1 inverts fully.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
amountis outside 0..1.
Kuwahara(int, float)
Smooths while keeping edges, with the Kuwahara filter as ImageMagick's -kuwahara defines it: of the four (r + 1) squares that
have the pixel as a corner, the one whose luma varies least gives the pixel its value, sampled at that square's middle. With
sigma above 0 the image is blurred first with ImageMagick's kernel for radius x sigma (a Gaussian of σ out to the radius). The
variances come from summed-area tables, so the cost does not grow with the radius.
public RasterOps Kuwahara(int radius = 3, float sigma = 0)
Parameters
radiusintThe radius in pixels, from 1 to 100.
sigmafloatThe blur before, in pixels, from 0 (none) to 100.
Returns
- RasterOps
This builder.
Examples
// Flattens texture into patches while keeping edges; a small blur first, as ImageMagick's -kuwahara 4x1.
using Raster smooth = photo.Derive(ops => ops.Kuwahara(4, sigma: 1), Ct);
Exceptions
- ArgumentOutOfRangeException
radiusis outside 1..100, orsigmais outside 0..100.
LensBlur(float, LensBlurOptions?)
Blurs as an out-of-focus lens does: each point spreads into the aperture's shape, a disc or a polygon of 5 to 12 blades, so small lights become discs, unlike a Gaussian's soft spots. Works in linear light by default, since a lens adds light; HighlightGain makes bright lights bloom. The cost does not grow with the radius: the blur runs by FFT on tiles. Edges repeat the edge pixel.
public RasterOps LensBlur(float radius, LensBlurOptions? options = null)
Parameters
radiusfloatThe aperture's radius in pixels, from 0 (changes nothing) to 128.
optionsLensBlurOptionsThe aperture and highlights, or null for a round aperture in linear light.
Returns
- RasterOps
This builder.
Examples
// Blur the background like a wide-open lens with a six-blade aperture: bright points become hexagons.
LensBlurOptions lens = new() { Blades = 6, Rotation = 15, HighlightGain = 4, HighlightThreshold = 0.8f };
photo.Apply(ops => ops.Within(new Rect(0, 0, photo.Width, photo.Height / 3), o => o.LensBlur(12, lens)), Ct);
Exceptions
- ArgumentOutOfRangeException
radiusis negative, not finite or above 128, or an option is out of range: blades other than 0 or 5 to 12, a rotation that is not finite, a gain below 1 or not finite, a threshold outside 0..1, or an undefined color space.
Level(float, float, float, float, float)
Stretches black..white to outputBlack..outputWhite
with a midtone gamma, as ImageMagick's -level and +level. See Level(float, float, float, float, float).
public RasterOps Level(float black = 0, float white = 1, float gamma = 1, float outputBlack = 0, float outputWhite = 1)
Parameters
blackfloatThe input that becomes
outputBlack, from 0 to 1.whitefloatThe input that becomes
outputWhite, from 0 to 1.gammafloatThe midtone gamma, above 0: above 1 brightens.
outputBlackfloatThe output for
black, from 0 to 1.outputWhitefloatThe output for
white, from 0 to 1.
Returns
- RasterOps
This builder.
Examples
// A basic tone panel: levels with a midtone lift, a gentle S-curve, and a warm tint in the midtones. The three steps run as
// one pass over the pixels.
raster.Apply(o => o
.Level(black: 0.04f, white: 0.96f, gamma: 1.1f)
.SigmoidalContrast(4, midpoint: 0.5f)
.Tint(new Rgba8(255, 200, 150, 255), 0.15f), Ct);
raster.Save("duck-toned.jpg");
Exceptions
- ArgumentOutOfRangeException
A value is out of range, or
blackequalswhite.
Lighting(Light, LightingModel, LightingOptions?)
Lights the image as a height field with the SVG 1.1 lighting filters (feDiffuseLighting and feSpecularLighting), with Skia's parameters: the height channel (alpha by default) times SurfaceScale is a surface, its normal comes from SVG's Sobel stencils (with SVG's own stencils on the edges and corners), and the light's color is scaled by N·L (Diffuse(float)) or (N·H)^shininess (Specular(float, float)). The result is the light map (opaque for diffuse; for specular, alpha is the largest color channel), or, with Blend, the light map blended onto the image, which keeps its alpha. Light is computed on stored values, as Skia does in its working space; SVG's default of linear light is not applied.
public RasterOps Lighting(Light light, LightingModel model, LightingOptions? options = null)
Parameters
lightLightThe light: DistantLight, PointLight or SpotLight, in pixel coordinates.
modelLightingModelHow the surface reflects: Diffuse(float) or Specular(float, float); the default value is a diffuse model with kd 0, which is black.
optionsLightingOptionsThe surface scale, height channel and blend; null for the defaults.
Returns
- RasterOps
This builder.
Examples
// A photo's luminance as the height: light areas stand up. SurfaceScale is the height of white, in pixels.
LightingOptions relief = new() { Height = HeightSource.Luminance, SurfaceScale = 6 };
using Raster lit = photo.Derive(ops => ops.Lighting(new DistantLight(300, 50), LightingModel.Diffuse(), relief), Ct);
// The same light blended onto the photo instead of replacing it.
using Raster shaded = photo.Derive(ops => ops.Lighting(new DistantLight(300, 50), LightingModel.Diffuse(1.3f), relief with { Blend = BlendMode.Overlay }), Ct);
Exceptions
- ArgumentNullException
lightis null.
LocalContrast(float, float)
Brings out local detail, as ImageMagick's -local-contrast: L* is pushed away from a wide blur of itself by
strength, so large-scale light changes less than detail. a* and b* are kept.
public RasterOps LocalContrast(float radius = 0.1, float strength = 0.125)
Parameters
radiusfloatThe blur radius as a fraction of 20% of the longer side, above 0 and at most 1; the default 0.1 blurs over 2%.
strengthfloatHow strongly detail is raised, 0 or more; the default 0.125 is ImageMagick's 12.5%.
Returns
- RasterOps
This builder.
Examples
// Bring out detail in a flat, foggy landscape: CLAHE on 8 × 8 tiles, then ImageMagick's local contrast.
raster.Apply(o => o.Clahe(tilesX: 8, tilesY: 8, clipLimit: 2).LocalContrast(radius: 0.1f, strength: 0.15f), Ct);
Remarks
Two lightness planes, 4 bytes a pixel each, count against MaxTotalBytes. Inside a rectangle or mask, the scope is its image.
Exceptions
- ArgumentOutOfRangeException
An argument is out of range.
LuminanceToAlpha()
Sets alpha to the luminance of the stored values, 0.212656 R + 0.715158 G + 0.072186 B (the Rec. 709 weights as ImageMagick
derives them from the sRGB primaries), and keeps the color, exactly as ImageMagick's -alpha copy does; on a gray raster this
turns the gray into alpha. A color matrix, so it fuses with neighbouring color steps.
To also black out the color, as Skia's luma filter does, follow it with OnChannels(ColorChannels.Color, o => o.FillColor(Rgba8.Black)).
public RasterOps LuminanceToAlpha()
Returns
- RasterOps
This builder.
Examples
using Raster alpha = photo.Derive(ops => ops.AlphaToGray(), Ct); // see the transparency as gray
using Raster cutout = photo.Derive(ops => ops.CopyAlpha(new Mask(matte)), Ct); // a gray image becomes the alpha
using Raster onWhite = cutout.Derive(ops => ops.Flatten(Rgba8.White), Ct); // composite onto white, opaque
using Raster luma = photo.Derive(ops => ops.LuminanceToAlpha(), Ct); // brightness becomes alpha
MakeTransparent(Rgba8, float, float)
Makes pixels within tolerance of color transparent, keeping their color, by ImageMagick's
-fuzz distance, so with no softness the result equals ImageMagick's -fuzz with -transparent. softness ramps
alpha up over the next band of distance, for antialiased edges and green screens.
public RasterOps MakeTransparent(Rgba8 color, float tolerance = 0, float softness = 0)
Parameters
colorRgba8The color to remove, with its alpha (opaque for most keys).
tolerancefloatThe color distance that becomes fully transparent, from 0 (the exact color) to 1 (every color).
softnessfloatThe band of distance beyond the tolerance over which alpha returns to full; 0 for a hard edge.
Returns
- RasterOps
This builder.
Examples
// Remove a green screen: within 0.15 of pure green becomes transparent, and alpha ramps back over the next 0.1 for soft edges.
photo.Apply(ops => ops.MakeTransparent(new Rgba8(0, 177, 64, 255), tolerance: 0.15f, softness: 0.1f), Ct);
Exceptions
- ArgumentOutOfRangeException
toleranceis outside 0..1, orsoftnessis negative or not finite.
Median(int, bool)
Replaces each channel with its median over the (2r + 1) square around the pixel, as ImageMagick's -statistic Median does: removes salt-and-pepper noise while keeping edges. Works on stored values, so 8 and 16-bit results are exact; edges repeat the edge pixel. The cost per pixel does not grow with the radius on byte types.
public RasterOps Median(int radius, bool includeAlpha = false)
Parameters
radiusintThe radius in pixels, from 0 (changes nothing) to 100.
includeAlphaboolWhether alpha gets its own median too; by default it is kept.
Returns
- RasterOps
This builder.
Examples
// Salt-and-pepper noise disappears and edges stay sharp; radius 2 is a 5 × 5 window.
photo.Apply(ops => ops.Median(2), Ct);
Exceptions
- ArgumentOutOfRangeException
radiusis negative or above 100.
MergeDuplicates(float)
Removes each frame equal to the one before it and adds its delay to the frame that stays, as ImageMagick's -layers RemoveDups: a screen recording that sat still for seconds becomes one long frame. What is on screen at every moment is unchanged. Removed frames take their metadata with them.
public RasterOps MergeDuplicates(float tolerance = 0)
Parameters
tolerancefloatHow far a pixel may differ and still count as equal, by ImageMagick's -fuzz distance, from 0 (the default, exact) to 1.
Returns
- RasterOps
This builder.
Examples
// Shrink a screen recording: merge frames that barely change, drop frames no viewer shows, then resample to 25 fps.
recording.Apply(ops => ops.MergeDuplicates(tolerance: 0.01f).DropZeroDelay().Retime(25), Ct);
recording.Save("recording.gif");
Exceptions
- ArgumentOutOfRangeException
toleranceis outside 0 to 1.
Morphology(MorphologyOp, StructuringElement, int)
Flat morphology: each channel's maximum (dilate) or minimum (erode) over shape around each pixel, or one
of their combinations, as ImageMagick's -morphology. Works on stored values, alpha included, so 8 and 16-bit results are
exact; Gradient, TopHat and BottomHat
keep alpha. Edges repeat the edge pixel. Rectangles cost the same per pixel at any size; other shapes grow with their height.
public RasterOps Morphology(MorphologyOp op, StructuringElement shape, int iterations = 1)
Parameters
opMorphologyOpThe operation.
shapeStructuringElementThe structuring element.
iterationsintHow many times each dilation and erosion runs, 1 to 100: Open with 2 erodes twice, then dilates twice.
Returns
- RasterOps
This builder.
Examples
// Close removes dark specks smaller than the shape (dust and toner dots on the paper) and keeps strokes wider than it;
// Open does the opposite, for light pinholes in dark areas.
using Raster<Gray8> scan = Raster.Load<Gray8>("scan.tif");
scan.Apply(o => o.Morphology(MorphologyOp.Close, StructuringElement.Disk(1)), Ct);
// The outlines of shapes, and the light details smaller than a disk.
using Raster outlines = scan.Derive(o => o.Morphology(MorphologyOp.Gradient, StructuringElement.Square(1)), Ct);
using Raster details = scan.Derive(o => o.Morphology(MorphologyOp.TopHat, StructuringElement.Disk(5)), Ct);
Exceptions
- ArgumentOutOfRangeException
opis not defined, oriterationsis outside 1 to 100.
MotionBlur(float, float, float, bool)
Streaks the image along a direction, as a camera moving during the exposure, with ImageMagick's -motion-blur meaning: each
pixel averages 2⌈radius⌉ + 1 samples one pixel apart, from itself toward angle, weighted by a Gaussian of
sigma from the pixel. Samples between pixels are read bilinearly; edges repeat the edge pixel.
public RasterOps MotionBlur(float radius, float sigma, float angle, bool centered = false)
Parameters
radiusfloatHalf the streak's length in pixels, from 0 (changes nothing) to 127.
sigmafloatHow fast the weights fall along the streak, above 0.
anglefloatThe direction in degrees, clockwise from the x axis (y points down).
centeredboolWhether the streak runs both ways from the pixel, instead of only toward
angle.
Returns
- RasterOps
This builder.
Examples
using Raster moving = photo.Derive(ops => ops.MotionBlur(radius: 12, sigma: 4, angle: 15), Ct); // a streak toward 15°
using Raster spinning = photo.Derive(ops => ops.RotationalBlur(8), Ct); // 8° around the center
using Raster zooming = photo.Derive(ops => ops.ZoomBlur(0.2f, new System.Numerics.Vector2(320, 200)), Ct);
Exceptions
- ArgumentOutOfRangeException
An argument is not finite or out of range.
Normalize(bool, bool)
ContrastStretch(float, float, bool, bool) at ImageMagick's -normalize points: the darkest 2% of the pixels become black and the lightest 1% white.
public RasterOps Normalize(bool linked = true, bool perFrame = false)
Parameters
linkedboolWhether the channels share one pair of points (the default) or each gets its own.
perFrameboolWhether each frame is measured alone.
Returns
- RasterOps
This builder.
Examples
// Fix a dull scan: stretch it to the full range, clipping the darkest 2% and lightest 1%, then set the midtones.
raster.Apply(o => o.Normalize().AutoGamma(), Ct);
// Or stretch each channel on its own, which also removes a cast.
raster.Apply(o => o.AutoLevel(linked: false), Ct);
// Measured steps measure only their scope: here the sky alone is stretched.
raster.Apply(o => o.Within(new Rect(0, 0, raster.Width, raster.Height / 3), sky => sky.AutoLevel()), Ct);
Offset(int, int, EdgeMode, Rgba8)
Moves the image by whole pixels, right by dx and down by dy, with no resampling. What
leaves one side comes in at the other with Wrap (the default, ImageMagick's -roll); with
Transparent the uncovered strip is background, as Skia's Offset filter leaves it.
public RasterOps Offset(int dx, int dy, EdgeMode edges = EdgeMode.Wrap, Rgba8 background = default)
Parameters
dxintThe horizontal move, in pixels.
dyintThe vertical move, in pixels.
edgesEdgeModeWhat fills the uncovered strips.
backgroundRgba8The color of uncovered strips under Transparent.
Returns
- RasterOps
This builder.
Examples
// Roll the image half way round, so its edges meet in the middle, which shows whether it tiles seamlessly.
using Raster rolled = photo.Derive(ops => ops.Offset(photo.Width / 2, photo.Height / 2), Ct);
// Fill a 1920 × 1080 wallpaper with copies of the duck's head.
using Raster wallpaper = photo.Derive(ops => ops.Tile(1920, 1080, source: new Rect(380, 60, 160, 160)), Ct);
Exceptions
- ArgumentOutOfRangeException
edgesis not defined.
OilPaint(int, int)
Makes the image look painted, as ImageMagick's -paint does: around each pixel, in the (2r + 1) square, pixels are sorted into
levels bins by intensity, and the pixel becomes a pixel of the most common bin, unchanged. With 256 levels
on 8-bit images the result is ImageMagick's exactly; fewer levels make larger, flatter strokes. Works on stored values; the
histogram slides along each row, so a larger radius costs little more per pixel than the window's size.
public RasterOps OilPaint(int radius = 3, int levels = 20)
Parameters
radiusintThe brush radius in pixels, from 1 to 50.
levelsintThe number of intensity bins, from 2 to 256.
Returns
- RasterOps
This builder.
Examples
using Raster painted = photo.Derive(ops => ops.OilPaint(radius: 4, levels: 20), Ct);
using Raster magick = photo.Derive(ops => ops.OilPaint(3, levels: 256), Ct); // ImageMagick's -paint 3, pixel for pixel
Exceptions
- ArgumentOutOfRangeException
radiusis outside 1..50, orlevelsis outside 2..256.
OnChannels(ColorChannels, Action<RasterOps>)
Runs the operations build adds and keeps their result only in channels, as ImageMagick's
-channel does: OnChannels(ColorChannels.Alpha, o => o.Blur(2)) softens only the alpha. Channels are the working RGBA,
with a gray raster's red, green and blue its gray value. Color steps that fuse into one matrix (Brightness, ShuffleChannels,
a color matrix) become that matrix with the other channels left as they are, so they cost nothing extra; other chains run
once and the other channels are restored. Combines with Within in either order.
public RasterOps OnChannels(ColorChannels channels, Action<RasterOps> build)
Parameters
channelsColorChannelsThe channels the result is kept in.
buildAction<RasterOps>Adds the operations. Each must keep the size, as in Within(Rect, Action<RasterOps>).
Returns
- RasterOps
This builder.
Examples
// Soften only the alpha; invert only the red.
photo.Apply(ops => ops
.OnChannels(ColorChannels.Alpha, o => o.Blur(2))
.OnChannels(ColorChannels.Red, o => o.Invert()), Ct);
Exceptions
- ArgumentOutOfRangeException
channelsholds values that are not channels.- ArgumentNullException
buildis null.- ArgumentException
An operation inside would change the size or the color encoding; the message names it.
Opacity(float)
Multiplies alpha by amount. Has no effect on pixel types without alpha.
public RasterOps Opacity(float amount)
Parameters
amountfloat0 makes the image transparent, 1 changes nothing.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
amountis outside 0..1.
Pad(int, int, Rgba8, Anchor)
Enlarges the canvas to width × height, placing the image at anchor
and filling the new area with background.
public RasterOps Pad(int width, int height, Rgba8 background = default, Anchor anchor = Anchor.Center)
Parameters
widthintThe new width, at least the image's width.
heightintThe new height, at least the image's height.
backgroundRgba8The color of the new area. Defaults to transparent black.
anchorAnchorWhere the image sits on the new canvas. Defaults to the center, rounding toward the top left.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
A size is less than 1, or smaller than the image when the chain runs (use Crop(Rect) to shrink), or
anchoris not defined.
Pixelate(int, Point)
Pixelates: the image is cut into square cells, and every pixel of a cell becomes the cell's average, taken on premultiplied
values so transparent pixels do not darken it. Cells start at origin and repeat every
cellSize pixels both ways; cells cut by the image's edges average the pixels they hold. Inside
Within(Rect, Action<RasterOps>) cells stay on the image's grid and average whole cells, reading past the area.
public RasterOps Pixelate(int cellSize, Point origin = default)
Parameters
cellSizeintThe side of a cell in pixels, from 1 (changes nothing) to 4096.
originPointWhere a cell's top-left corner falls, in the raster's coordinates; the grid repeats from there both ways.
Returns
- RasterOps
This builder.
Examples
// 12-pixel cells, each the average of what it covers.
using Raster blocks = photo.Derive(ops => ops.Pixelate(12), Ct);
Exceptions
- ArgumentOutOfRangeException
cellSizeis outside 1..4096.
Posterize(int, DitherMode)
Rounds red, green and blue to levels evenly spaced values each, as ImageMagick's -posterize, optionally
dithered: ordered dithering adds a fixed 8 × 8 pattern before rounding, Floyd–Steinberg spreads each value's rounding error to
its neighbours. Without dithering it is Posterize(int).
public RasterOps Posterize(int levels, DitherMode dither = DitherMode.None)
Parameters
levelsintValues per channel, from 2 to 256.
ditherDitherModeThe dithering. Defaults to None.
Returns
- RasterOps
This builder.
Examples
// A two-color poster, then a check of how it reads to someone with deuteranopia.
raster.Apply(o => o.Duotone(Rgba8.FromHex("#1b2a49"), Rgba8.FromHex("#f2c14e")).Posterize(4, DitherMode.Ordered), Ct);
using Raster<Rgba8> preview = raster.Derive(o => o.SimulateColorBlindness(ColorVisionDeficiency.Deuteranopia), Ct);
// High contrast for low vision: gray, lightness inverted so dark becomes light, and more contrast.
using Raster<Rgba8> readable = raster.Derive(o => o.HighContrast(grayscale: true, ContrastInvert.Lightness, contrast: 0.3f), Ct);
Exceptions
- ArgumentOutOfRangeException
levelsis outside 2 to 256, orditheris not defined.
QuadDistort(Vector2, Vector2, Vector2, Vector2, TransformOptions?)
Moves the image's four corners to four points, bending it in perspective: ImageMagick's Perspective distort. Corners are pixel edges, so the top-right corner of a 100-pixel-wide image is (100, 0).
public RasterOps QuadDistort(Vector2 topLeft, Vector2 topRight, Vector2 bottomRight, Vector2 bottomLeft, TransformOptions? options = null)
Parameters
topLeftVector2Where the top-left corner goes.
topRightVector2Where the top-right corner goes.
bottomRightVector2Where the bottom-right corner goes.
bottomLeftVector2Where the bottom-left corner goes.
optionsTransformOptionsThe filter, edges, background and viewport, or null for the defaults.
Returns
- RasterOps
This builder.
Examples
// Pin the image onto a trapezoid, as if it lay on a table: its corners go to these four points (pixel edges, so the
// image's own corners are (0, 0) and (640, 480)).
using Raster onTable = photo.Derive(ops => ops.QuadDistort(new(200, 0), new(440, 0), new(640, 300), new(0, 300)), Ct);
Exceptions
- ArgumentException
A point is not finite, three of them lie on one line, or the viewport is empty.
Quantize(PaletteOptions?)
Reduces each frame to at most MaxColors colors, as a palette format would, but keeps the pixel type: an Rgba16 image stays Rgba16 with at most that many distinct values. Each frame gets its own palette (its own colors when they fit, Wu's quantizer otherwise) unless FixedPalette fixes one, and is dithered as the options say. Use ToIndexed(PaletteOptions?, int) for the indices themselves.
public RasterOps Quantize(PaletteOptions? options = null)
Parameters
optionsPaletteOptionsThe color limit, dithering, refinement and matching, or null for Default.
Returns
- RasterOps
This builder.
Examples
// A 16-color poster with Atkinson's dither; the pixel type stays as it was.
photo.Apply(ops => ops.Quantize(new PaletteOptions { MaxColors = 16, Dither = DitherMode.Atkinson }), Ct);
photo.Save("poster.png");
Reach(Action<RasterOps>)
Returns how far a chain reads past each output pixel: the sum of its steps' reaches. Pixel-by-pixel steps (color matrices, arithmetic, color filters, blending a color, keying) reach nothing; blurs, convolutions, morphology, glows and drop shadows reach as far as their kernels and offsets. A step whose reach is unbounded or unknown (a resize, a geometric transform, a histogram step, a custom IRasterOperation) makes the whole chain's reach unknown.
public static OperationReach? Reach(Action<RasterOps> build)
Parameters
buildAction<RasterOps>Records the chain, as for Apply(Action<RasterOps>, CancellationToken); it is recorded, not run.
Returns
- OperationReach?
The reach, or null when some step's reach is unknown.
Examples
// How far a chain reads around each pixel: run it on a part of a picture padded by this much, and the part comes out as it
// would in the whole picture.
OperationReach? reach = RasterOps.Reach(ops => ops.Blur(3).Glow(4, Rgba8.White));
if (reach is OperationReach r)
{
Console.WriteLine($"pad by {r.X} × {r.Y}");
}
// A resize reads the whole image: its reach is unknown.
Assert.Null(RasterOps.Reach(ops => ops.Resize(100, 100)));
Exceptions
- ArgumentNullException
buildis null.
Remap(Palette, DitherMode, float)
Maps every pixel onto palette, as ImageMagick's -remap: a brand palette, a display's inks, or the
palette of another image. The pixel type is kept, and so is each pixel's alpha when the palette is opaque.
public RasterOps Remap(Palette palette, DitherMode dither = DitherMode.FloydSteinberg, float strength = 1)
Parameters
palettePaletteThe palette.
ditherDitherModeHow the error is spread. Defaults to FloydSteinberg.
strengthfloatHow strongly, from 0 (the nearest color) to 1 (the default).
Returns
- RasterOps
This builder.
Examples
// Map onto a fixed palette: here an e-ink display's six inks.
Palette inks = Palette.FromColors([Rgba8.Black, Rgba8.White, new(255, 0, 0, 255), new(255, 255, 0, 255), new(0, 0, 255, 255), new(0, 255, 0, 255)]);
photo.Apply(ops => ops.Remap(inks, DitherMode.FloydSteinberg), Ct);
Exceptions
- ArgumentNullException
paletteis null.- ArgumentOutOfRangeException
ditheris not defined, orstrengthis outside 0 to 1.
ReplaceColor(Rgba8, Rgba8, float)
Replaces every pixel within tolerance of from with to, by ImageMagick's
-fuzz distance, as ImageMagick's -fill with -opaque does.
public RasterOps ReplaceColor(Rgba8 from, Rgba8 to, float tolerance = 0)
Parameters
fromRgba8The color to replace, with its alpha.
toRgba8The color to put in its place.
tolerancefloatThe color distance, from 0 (the exact color) to 1 (every color).
Returns
- RasterOps
This builder.
Examples
photo.Apply(ops => ops.ReplaceColor(Rgba8.White, new Rgba8(250, 245, 230, 255), tolerance: 0.05f), Ct);
Exceptions
- ArgumentOutOfRangeException
toleranceis outside 0..1.
Resize(int, int, ResampleFilter, ColorSpace)
Resizes the image to width × height. Pass 0 for one dimension to keep the aspect ratio.
Resizing to the current size changes nothing. A Crop(Rect) just before a resize is merged into it, so only the
crop rectangle is read.
public RasterOps Resize(int width, int height, ResampleFilter filter = ResampleFilter.Bicubic, ColorSpace colorSpace = ColorSpace.Encoded)
Parameters
widthintThe new width, or 0 to derive it from
height.heightintThe new height, or 0 to derive it from
width.filterResampleFilterThe resampling kernel. Defaults to Bicubic.
colorSpaceColorSpaceWhere pixels are blended. Defaults to Encoded.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
A size is negative, or both are 0.
Retime(double)
Resamples the animation to framesPerSecond, as ffmpeg's fps filter: fixed ticks, each showing the frame
visible when it starts, with neighbours that show the same frame merged. No frame is ever added and the total duration is
kept; frames shorter than a tick may be dropped. A rate at or above the animation's own changes nothing. Browsers show
GIF delays under 20 ms as 100 ms, so 50 is the useful ceiling for GIF.
public RasterOps Retime(double framesPerSecond)
Parameters
framesPerSeconddoubleThe rate, more than 0 and at most 1,000.
Returns
- RasterOps
This builder.
Examples
// Shrink a screen recording: merge frames that barely change, drop frames no viewer shows, then resample to 25 fps.
recording.Apply(ops => ops.MergeDuplicates(tolerance: 0.01f).DropZeroDelay().Retime(25), Ct);
recording.Save("recording.gif");
Exceptions
- ArgumentOutOfRangeException
framesPerSecondis out of range or not finite.
Reverse()
Plays the animation backwards; each frame keeps its delay and metadata.
public RasterOps Reverse()
Returns
- RasterOps
This builder.
Examples
// Twice as fast, then backwards: a boomerang clip is the clip followed by its reverse.
using Raster fast = clip.Derive(ops => ops.ChangeSpeed(2), Ct);
using Raster backwards = fast.Derive(ops => ops.Reverse(), Ct);
Rotate(float, ResampleFilter, Rgba8)
Rotates the image clockwise. Multiples of 90° move pixels exactly; other angles resample onto a canvas the size of the
rotated bounding box, with the corners filled with background.
public RasterOps Rotate(float degrees, ResampleFilter filter = ResampleFilter.Bicubic, Rgba8 background = default)
Parameters
degreesfloatThe angle, clockwise. Negative angles turn counter-clockwise, so −90 equals 270.
filterResampleFilterThe resampling kernel for angles that are not multiples of 90°. Defaults to Bicubic.
backgroundRgba8The color of the canvas outside the rotated image. Defaults to transparent black.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
degreesis not finite, orfilteris not defined.
RotationalBlur(float, Vector2?)
Spins the image around center, as ImageMagick's -rotational-blur: each pixel averages samples along an arc
of degrees centered on it, about one per pixel of arc (at most 256), read bilinearly. Pixels far from the
center blur most; the center does not move.
public RasterOps RotationalBlur(float degrees, Vector2? center = null)
Parameters
degreesfloatThe arc in degrees, from 0 (changes nothing) to 360.
centerVector2?The center in pixels, pixel centers at +0.5, or null for the image's center.
Returns
- RasterOps
This builder.
Examples
using Raster moving = photo.Derive(ops => ops.MotionBlur(radius: 12, sigma: 4, angle: 15), Ct); // a streak toward 15°
using Raster spinning = photo.Derive(ops => ops.RotationalBlur(8), Ct); // 8° around the center
using Raster zooming = photo.Derive(ops => ops.ZoomBlur(0.2f, new System.Numerics.Vector2(320, 200)), Ct);
Exceptions
- ArgumentOutOfRangeException
degreesis outside 0..360, or the center is not finite.
Saturation(float)
Mixes each color with its luma: 1 changes nothing, 0 gives gray, above 1 oversaturates. See Saturation(float).
public RasterOps Saturation(float amount)
Parameters
amountfloatThe factor, 0 or more.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
amountis negative or not finite.
Sepia(float)
Tints toward sepia. See Sepia(float).
public RasterOps Sepia(float amount = 1)
Parameters
amountfloat0 changes nothing, 1 gives full sepia.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
amountis outside 0..1.
Shade(float, float, bool)
Shades the image as ImageMagick's -shade does: the luminance is a height field, and each pixel becomes the Lambertian
shading of its surface normal by a distant light at azimuth and elevation, a gray
relief; with colored the shading multiplies the image's own colors instead, as +shade does. Identical to
ImageMagick at 8 bits; alpha is kept; edges repeat the edge pixel.
public RasterOps Shade(float azimuth = 30, float elevation = 30, bool colored = false)
Parameters
azimuthfloatThe light's direction in the image plane, in degrees counterclockwise from the right with y up, as ImageMagick's.
elevationfloatThe light's angle above the image plane, in degrees, from 0 to 90; flat areas get sin(elevation).
coloredboolWhether the shading multiplies the colors (+shade) rather than replacing them with gray (-shade).
Returns
- RasterOps
This builder.
Examples
// ImageMagick's -shade 30x30 (identical at 8 bits) and +shade 120x45.
using Raster gray = photo.Derive(ops => ops.Shade(azimuth: 30, elevation: 30), Ct);
using Raster colored = photo.Derive(ops => ops.Shade(azimuth: 120, elevation: 45, colored: true), Ct);
Exceptions
- ArgumentOutOfRangeException
azimuthis not finite, orelevationis not from 0 to 90.
Sharpen(float, float)
Sharpens with an unsharp mask: out = src + amount × (src − Blur(sigma)).
public RasterOps Sharpen(float amount = 1, float sigma = 1)
Parameters
amountfloatHow strongly to sharpen; 0 changes nothing. Defaults to 1.
sigmafloatThe blur radius that sets which details are sharpened, in pixels. Defaults to 1.
Returns
- RasterOps
This builder.
Exceptions
- ArgumentOutOfRangeException
An argument is negative or not finite, or
sigmais 0 or above 100.
ShuffleChannels(ChannelSource, ChannelSource, ChannelSource, ChannelSource)
Rearranges the working RGBA channels: each output channel takes the input channel, or the constant, its argument names. Swapping red and blue, or copying green into alpha, is one color matrix, so it fuses with neighbouring color steps into one pass.
public RasterOps ShuffleChannels(ChannelSource red, ChannelSource green, ChannelSource blue, ChannelSource alpha)
Parameters
redChannelSourceWhere the output's red comes from.
greenChannelSourceWhere the output's green comes from.
blueChannelSourceWhere the output's blue comes from.
alphaChannelSourceWhere the output's alpha comes from. Has no effect on pixel types without alpha.
Returns
- RasterOps
This builder.
Examples
// Swap red and blue: one color matrix, fused with the other color steps into one pass.
photo.Apply(ops => ops
.ShuffleChannels(ChannelSource.Blue, ChannelSource.Green, ChannelSource.Red, ChannelSource.Alpha)
.Brightness(1.05f), Ct);
Exceptions
- ArgumentOutOfRangeException
A source is not defined.
SigmoidalContrast(float, float, bool)
Adds (or removes) contrast with ImageMagick's scaled logistic curve, which never clips. See SigmoidalContrast(float, float, bool).
public RasterOps SigmoidalContrast(float contrast, float midpoint = 0.5, bool increase = true)
Parameters
contrastfloatHow steep the curve is, 0 or more: 3 is gentle, 10 strong.
midpointfloatWhere the curve is steepest, from 0 to 1. Defaults to 0.5.
increaseboolWhether contrast increases (the default) or decreases.
Returns
- RasterOps
This builder.
Examples
// A basic tone panel: levels with a midtone lift, a gentle S-curve, and a warm tint in the midtones. The three steps run as
// one pass over the pixels.
raster.Apply(o => o
.Level(black: 0.04f, white: 0.96f, gamma: 1.1f)
.SigmoidalContrast(4, midpoint: 0.5f)
.Tint(new Rgba8(255, 200, 150, 255), 0.15f), Ct);
raster.Save("duck-toned.jpg");
Exceptions
- ArgumentOutOfRangeException
An argument is out of range.
SimulateColorBlindness(ColorVisionDeficiency, float)
Shows how the image looks with a color vision deficiency. See SimulateColorBlindness(ColorVisionDeficiency, float).
public RasterOps SimulateColorBlindness(ColorVisionDeficiency kind, float severity = 1)
Parameters
kindColorVisionDeficiencyThe deficiency.
severityfloatFrom 0 (normal vision) to 1. Defaults to 1.
Returns
- RasterOps
This builder.
Examples
// A two-color poster, then a check of how it reads to someone with deuteranopia.
raster.Apply(o => o.Duotone(Rgba8.FromHex("#1b2a49"), Rgba8.FromHex("#f2c14e")).Posterize(4, DitherMode.Ordered), Ct);
using Raster<Rgba8> preview = raster.Derive(o => o.SimulateColorBlindness(ColorVisionDeficiency.Deuteranopia), Ct);
// High contrast for low vision: gray, lightness inverted so dark becomes light, and more contrast.
using Raster<Rgba8> readable = raster.Derive(o => o.HighContrast(grayscale: true, ContrastInvert.Lightness, contrast: 0.3f), Ct);
Exceptions
- ArgumentOutOfRangeException
An argument is out of range.
Skew(float, float, TransformOptions?)
Shears the image about its center: vertical lines lean by degreesX (x moves by y × tan) and horizontal
lines by degreesY. The canvas grows to the sheared bounds unless a viewport is given.
public RasterOps Skew(float degreesX, float degreesY, TransformOptions? options = null)
Parameters
degreesXfloatThe horizontal shear angle, strictly between −90 and 90.
degreesYfloatThe vertical shear angle, strictly between −90 and 90.
optionsTransformOptionsThe filter, edges, background and viewport, or null for the defaults.
Returns
- RasterOps
This builder.
Examples
// Lean a banner 12° to the right, filling the uncovered corners with white; the canvas grows to fit.
using Raster banner = photo.Derive(ops => ops.Skew(12, 0, new TransformOptions { Background = Rgba8.White }), Ct);
// Skew a region in place: a viewport the size of the area keeps it the same size inside Within.
using Raster region = photo.Derive(ops => ops.Within(new Rect(100, 100, 200, 120), s => s.Skew(0, 8, new TransformOptions { Viewport = new Rect(0, 0, 200, 120) })), Ct);
Exceptions
- ArgumentOutOfRangeException
An angle is not finite or not strictly between −90 and 90.
- ArgumentException
The two shears together collapse the image (tan x × tan y = 1), or the viewport is empty.
Solarize(float)
Inverts red, green and blue values above threshold, as ImageMagick's -solarize. See Solarize(float).
public RasterOps Solarize(float threshold = 0.5)
Parameters
thresholdfloatThe level, from 0 to 1. Defaults to 0.5.
Returns
- RasterOps
This builder.
Examples
// A two-color poster, then a check of how it reads to someone with deuteranopia.
raster.Apply(o => o.Duotone(Rgba8.FromHex("#1b2a49"), Rgba8.FromHex("#f2c14e")).Posterize(4, DitherMode.Ordered), Ct);
using Raster<Rgba8> preview = raster.Derive(o => o.SimulateColorBlindness(ColorVisionDeficiency.Deuteranopia), Ct);
// High contrast for low vision: gray, lightness inverted so dark becomes light, and more contrast.
using Raster<Rgba8> readable = raster.Derive(o => o.HighContrast(grayscale: true, ContrastInvert.Lightness, contrast: 0.3f), Ct);
Exceptions
- ArgumentOutOfRangeException
thresholdis outside 0..1.
Spread(float, ulong)
Scatters pixels, as ImageMagick's -spread does: each pixel takes the value of a random pixel at most
radius away (a whole-pixel offset in the disc; edges repeat the edge pixel). The offsets come from a hash of
the seed and the pixel's position, so the same seed gives the same pixels on any machine and any number of cores.
public RasterOps Spread(float radius, ulong seed = 0)
Parameters
radiusfloatThe farthest a value moves, in pixels, from 0 to 1000; below 1 nothing moves.
seedulongPicks the pattern; the same seed gives the same result.
Returns
- RasterOps
This builder.
Examples
// Frosted glass: every pixel takes a neighbour's value up to 3 pixels away; the same seed gives the same result.
using Raster frosted = photo.Derive(ops => ops.Spread(3, seed: 42), Ct);
Exceptions
- ArgumentOutOfRangeException
radiusis outside 0..1000.
Threshold(float, ThresholdMode, Rgba8?, Rgba8?)
Makes a two-color image: pixels above level take above, the others
below, with alpha kept. See Threshold(float, ThresholdMode, Rgba8?, Rgba8?).
public RasterOps Threshold(float level = 0.5, ThresholdMode mode = ThresholdMode.Luminance, Rgba8? below = null, Rgba8? above = null)
Parameters
levelfloatThe level, from 0 to 1. Defaults to 0.5.
modeThresholdModeWhat is measured. Defaults to Luminance.
belowRgba8?The lower color, or null for black.
aboveRgba8?The upper color, or null for white.
Returns
- RasterOps
This builder.
Examples
// Two colors: navy below half luminance, cream above; alpha is kept.
using Raster<Rgba8> stamp = raster.Derive(o => o.Threshold(0.5f, ThresholdMode.Luminance, Rgba8.Navy, new Rgba8(250, 240, 220, 255)), Ct);
Exceptions
- ArgumentOutOfRangeException
levelis outside 0..1, ormodeis not defined.
Tile(int, int, Point, Rect?)
Makes a new width × height canvas filled by repeating the image, or the
source rectangle of it, with one copy's top-left corner at origin, as Skia's Tile
filter and ImageMagick's tile: fill do. Pixels are copied exactly.
public RasterOps Tile(int width, int height, Point origin = default, Rect? source = null)
Parameters
widthintThe canvas width, at least 1.
heightintThe canvas height, at least 1.
originPointWhere one copy's top-left corner goes; copies repeat from there in every direction.
sourceRect?The rectangle to repeat, inside the image, or null (the default) for the whole image.
Returns
- RasterOps
This builder.
Examples
// Roll the image half way round, so its edges meet in the middle, which shows whether it tiles seamlessly.
using Raster rolled = photo.Derive(ops => ops.Offset(photo.Width / 2, photo.Height / 2), Ct);
// Fill a 1920 × 1080 wallpaper with copies of the duck's head.
using Raster wallpaper = photo.Derive(ops => ops.Tile(1920, 1080, source: new Rect(380, 60, 160, 160)), Ct);
Exceptions
- ArgumentOutOfRangeException
A size is less than 1, the rectangle is empty, or it leaves the image when the chain runs.
Tint(Rgba8, float)
Pushes midtones toward color and keeps black and white, as ImageMagick's -tint. See Tint(Rgba8, float).
public RasterOps Tint(Rgba8 color, float amount = 1)
Parameters
Returns
- RasterOps
This builder.
Examples
// A basic tone panel: levels with a midtone lift, a gentle S-curve, and a warm tint in the midtones. The three steps run as
// one pass over the pixels.
raster.Apply(o => o
.Level(black: 0.04f, white: 0.96f, gamma: 1.1f)
.SigmoidalContrast(4, midpoint: 0.5f)
.Tint(new Rgba8(255, 200, 150, 255), 0.15f), Ct);
raster.Save("duck-toned.jpg");
Exceptions
- ArgumentOutOfRangeException
amountis outside 0..1.
ToneMap(ToneMapping, double?)
Maps HDR linear light into 0..1: pixel values are read as linear light with reference white at 1.0 (as RgbaF32, RgbaF16 and RgbF32 rasters hold PQ and HLG images converted to a linear encoding), and the tone curve brings the brightest down to 1 on max(R, G, B), which keeps hue. Gray pixels map their value; CMYK pixels are left alone. The metadata's Hdr is cleared, as the pixels are no longer HDR.
public RasterOps ToneMap(ToneMapping method = ToneMapping.Bt2390, double? sourcePeakNits = null)
Parameters
methodToneMappingThe curve. Defaults to Bt2390.
sourcePeakNitsdouble?The brightest light in the image, in cd/m² (reference white is 203), or null to take it from the metadata's Hdr (MaxCLL, then the mastering peak), else 1,000.
Returns
- RasterOps
This builder.
Examples
// HDR to SDR tone maps by default (BT.2390, source peak from the file's mDCV/cLLI, else 1,000 cd/m²).
using Raster<Rgb8> web = hdr.ConvertColor<Rgb8>(ColorProfile.Srgb);
// Or choose the curve and peak; Clip turns tone mapping off.
using Raster<Rgb8> soft = hdr.ConvertColor<Rgb8>(ColorProfile.Srgb, new ColorTransformOptions { ToneMapping = ToneMapping.Reinhard, SourcePeakNits = 4000 });
// Linear HDR pixels (1.0 = reference white, 203 cd/m²) can be tone mapped in place.
using Raster<RgbaF32> linear = hdr.ConvertColor<RgbaF32>(ColorProfile.LinearSrgb, new ColorTransformOptions { ToneMapping = ToneMapping.Clip });
linear.Apply(ops => ops.ToneMap(ToneMapping.Bt2390, sourcePeakNits: 1000));
Exceptions
- ArgumentOutOfRangeException
sourcePeakNitsis not a positive finite number.
Transform(Homography, TransformOptions?)
Transforms the image by a perspective (or affine) matrix that maps source positions to destination positions. Where the image shrinks or tilts away, each output pixel averages the ellipse its footprint covers in the source, so fine detail fades instead of aliasing.
public RasterOps Transform(Homography matrix, TransformOptions? options = null)
Parameters
matrixHomographyThe forward matrix.
optionsTransformOptionsThe filter, edges, background and viewport, or null for the defaults.
Returns
- RasterOps
This builder.
Examples
// Turn by 20° and shrink to 40% in one pass. Matrices map source positions to destination positions and compose with *,
// left first; shrinking averages each pixel's footprint, so fine detail fades instead of aliasing.
Matrix3x2 matrix = Matrix3x2.CreateRotation(MathF.PI / 9) * Matrix3x2.CreateScale(0.4f);
using Raster turned = photo.Derive(ops => ops.Transform(matrix), Ct);
// A 3D tilt, as CSS draws a flat element: rotate about the vertical axis and look at it from 800 pixels away.
Matrix4x4 tilt = Matrix4x4.CreateTranslation(-320, -240, 0) * Matrix4x4.CreateRotationY(0.5f) * new Matrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1f / 800, 0, 0, 0, 1);
using Raster tilted = photo.Derive(ops => ops.Transform(tilt), Ct);
Exceptions
- ArgumentException
The matrix is singular or not finite, or the viewport is empty. Without a viewport, the chain also throws when it is planned if the perspective sends a corner of the image to infinity or behind the viewer, naming the corner.
Transform(Matrix3x2, TransformOptions?)
Transforms the image by an affine matrix that maps source positions to destination positions, as Matrix3x2's factories build them (rotation is clockwise on screen). Pixels have the origin at the image's top-left corner and their centers at +0.5. The result is the transformed image's bounding box unless Viewport picks a rectangle; a pure scale equals Resize(int, int, ResampleFilter, ColorSpace) and a pure rotation equals Rotate(float, ResampleFilter, Rgba8).
public RasterOps Transform(Matrix3x2 matrix, TransformOptions? options = null)
Parameters
matrixMatrix3x2The forward matrix.
optionsTransformOptionsThe filter, edges, background and viewport, or null for the defaults.
Returns
- RasterOps
This builder.
Examples
// Turn by 20° and shrink to 40% in one pass. Matrices map source positions to destination positions and compose with *,
// left first; shrinking averages each pixel's footprint, so fine detail fades instead of aliasing.
Matrix3x2 matrix = Matrix3x2.CreateRotation(MathF.PI / 9) * Matrix3x2.CreateScale(0.4f);
using Raster turned = photo.Derive(ops => ops.Transform(matrix), Ct);
// A 3D tilt, as CSS draws a flat element: rotate about the vertical axis and look at it from 800 pixels away.
Matrix4x4 tilt = Matrix4x4.CreateTranslation(-320, -240, 0) * Matrix4x4.CreateRotationY(0.5f) * new Matrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1f / 800, 0, 0, 0, 1);
using Raster tilted = photo.Derive(ops => ops.Transform(tilt), Ct);
Exceptions
- ArgumentException
The matrix is singular or not finite, or the viewport is empty.
Transform(Matrix4x4, TransformOptions?)
Transforms the image by a 3D matrix applied to the image's plane at z = 0 and projected, as CSS matrix3d and Skia's
SkM44 draw a flat image; see FromMatrix4x4(Matrix4x4).
public RasterOps Transform(Matrix4x4 matrix, TransformOptions? options = null)
Parameters
matrixMatrix4x4The 3D matrix, in Matrix4x4's row-vector convention.
optionsTransformOptionsThe filter, edges, background and viewport, or null for the defaults.
Returns
- RasterOps
This builder.
Examples
// Turn by 20° and shrink to 40% in one pass. Matrices map source positions to destination positions and compose with *,
// left first; shrinking averages each pixel's footprint, so fine detail fades instead of aliasing.
Matrix3x2 matrix = Matrix3x2.CreateRotation(MathF.PI / 9) * Matrix3x2.CreateScale(0.4f);
using Raster turned = photo.Derive(ops => ops.Transform(matrix), Ct);
// A 3D tilt, as CSS draws a flat element: rotate about the vertical axis and look at it from 800 pixels away.
Matrix4x4 tilt = Matrix4x4.CreateTranslation(-320, -240, 0) * Matrix4x4.CreateRotationY(0.5f) * new Matrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1f / 800, 0, 0, 0, 1);
using Raster tilted = photo.Derive(ops => ops.Transform(tilt), Ct);
Exceptions
- ArgumentException
The projected matrix is singular or not finite, or the viewport is empty.
Trim(float, Rgba8?)
Removes the border: the rows and columns at the edges whose pixels all lie within tolerance of the
border color, by ImageMagick's -fuzz distance, so the rectangle equals ImageMagick's -trim. Every frame of an animation is
cropped to the union of the frames' rectangles, so they keep one size; an image that is all border is left as it is.
public RasterOps Trim(float tolerance = 0, Rgba8? color = null)
Parameters
tolerancefloatThe color distance still counted as border, from 0 (the exact color) to 1 (every color).
colorRgba8?The border color, or null (the default) for the top-left pixel's.
Returns
- RasterOps
This builder.
Examples
// Cut away the white margin, counting near-white (within 10% by ImageMagick's -fuzz distance) as margin too.
Rect content = scan.TrimBounds(tolerance: 0.1f);
scan.Apply(ops => ops.Trim(tolerance: 0.1f).Fit(400, 400), Ct);
Remarks
The size depends on the pixels, so the chain runs up to the trim, measures, and plans the rest from the real size; a trim
cannot run inside Within. TrimBounds(float, Rgba8?) returns the rectangle without changing anything.
Exceptions
- ArgumentOutOfRangeException
toleranceis outside 0..1.
Vignette(float, float, Rgba8?, Vector2?)
Darkens (or tints) the image toward its corners, outside an ellipse fitted to the image, with a soft edge: the shape of ImageMagick's -vignette, which blurs a drawn ellipse. The mask is computed per pixel, so its cost does not depend on the softness. Pixels are mixed with the color source-over, on premultiplied stored values.
public RasterOps Vignette(float radius = 1, float softness = 0.5, Rgba8? color = null, Vector2? center = null)
Parameters
radiusfloatThe ellipse's size as a fraction of the half-diagonal: at 1 the ellipse passes through the corners, at 0.7 it is about as wide as the image. The ellipse has the image's proportions.
softnessfloatThe share of the radius over which the edge fades, from 0 (hard) to 1: the fade is a Gaussian-blurred edge whose ±2σ spans softness × radius.
colorRgba8?The color toward the corners, with its alpha as its strength; black and opaque when null.
centerVector2?The ellipse's center in the raster's pixel coordinates (0, 0 is the top-left corner of the image); the image's middle when null.
Returns
- RasterOps
This builder.
Examples
// Darken the corners: the edge of the ellipse passes through the corners and fades over half the radius.
using Raster dark = photo.Derive(ops => ops.Vignette(), Ct);
// A tighter, softer, warm-white vignette, off-center toward the subject.
using Raster light = photo.Derive(
ops => ops.Vignette(0.6f, softness: 0.8f, color: new Rgba8(255, 245, 230, 255), center: new System.Numerics.Vector2(photo.Width * 0.4f, photo.Height * 0.5f)),
Ct);
Exceptions
- ArgumentOutOfRangeException
radiusis outside 0..10,softnessis outside 0..1, orcenteris not finite.
Warp(IWarp, SamplingOptions?)
Runs a warp: each output pixel shows the source point the warp maps it to, sampled as Transform(Homography, TransformOptions?) samples, so where the warp shrinks the image its fine detail fades instead of aliasing. Warps holds the built-in ones; FromFunction(Func<Vector2, Vector2>, Size?) or an own IWarp make others.
public RasterOps Warp(IWarp warp, SamplingOptions? options = null)
Parameters
warpIWarpThe warp.
optionsSamplingOptionsThe filter, color space, edges and background, or null for the defaults.
Returns
- RasterOps
This builder.
Examples
// Correct a wide-angle lens with the PanoTools coefficients a lens database gives (ImageMagick's Barrel), then swirl a
// square region in place; size-keeping warps run inside Within.
using Raster corrected = photo.Derive(ops => ops
.Warp(Warps.Barrel(0.0, -0.018, 0.0))
.Within(new Rect(300, 200, 200, 200), s => s.Warp(Warps.Swirl(90))), Ct);
// Size-changing ones: wrap the image into a circle, or bend it into an arc.
using Raster disc = photo.Derive(ops => ops.Warp(Warps.Polar(), new SamplingOptions { Background = Rgba8.White }), Ct);
using Raster arc = photo.Derive(ops => ops.Warp(Warps.Arc(120)), Ct);
// A magnifying glass over the duck's head, blending into the photo over 12 pixels.
using Raster loupe = photo.Derive(ops => ops.Warp(Warps.Magnifier(new Rect(380, 60, 160, 160), 2.5f, 12)), Ct);
Remarks
Warps that keep the size run inside Within; those that change it (Polar, DePolar, Arc, Wave) throw there.
Exceptions
- ArgumentNullException
warpis null.
WhiteBalance(Rgba8)
Applies WhiteBalance(Rgba8): makes neutral a neutral gray of its own luminance.
public RasterOps WhiteBalance(Rgba8 neutral)
Parameters
neutralRgba8A color that should be gray, such as a gray card's pixels.
Returns
- RasterOps
This builder.
Examples
// Correct a tungsten-lit photo, as a raw editor's temperature slider does.
raster.Apply(o => o.WhiteBalance(temperature: 3200), Ct);
// Or pick a gray card's color and make it neutral.
raster.Apply(o => o.WhiteBalance(new Rgba8(182, 170, 151, 255)), Ct);
// Or let the image tell: ImageMagick's gray world, or the brightest pixels as white.
raster.Apply(o => o.AutoWhiteBalance(WhiteBalanceMethod.GrayWorld), Ct);
raster.Apply(o => o.AutoWhiteBalance(WhiteBalanceMethod.WhitePatch), Ct);
Exceptions
- ArgumentOutOfRangeException
A channel of
neutralis 0, so no gain can make it gray.
WhiteBalance(float, float)
Applies WhiteBalance(float, float): corrects for a light of temperature kelvin.
public RasterOps WhiteBalance(float temperature, float tint = 0)
Parameters
temperaturefloatThe light's correlated color temperature, from 1,500 to 15,000 kelvin; 6504 changes almost nothing.
tintfloatThe light's offset from a black body's color, from −1 to 1; positive for a greener light.
Returns
- RasterOps
This builder.
Examples
// Correct a tungsten-lit photo, as a raw editor's temperature slider does.
raster.Apply(o => o.WhiteBalance(temperature: 3200), Ct);
// Or pick a gray card's color and make it neutral.
raster.Apply(o => o.WhiteBalance(new Rgba8(182, 170, 151, 255)), Ct);
// Or let the image tell: ImageMagick's gray world, or the brightest pixels as white.
raster.Apply(o => o.AutoWhiteBalance(WhiteBalanceMethod.GrayWorld), Ct);
raster.Apply(o => o.AutoWhiteBalance(WhiteBalanceMethod.WhitePatch), Ct);
Exceptions
- ArgumentOutOfRangeException
An argument is out of range.
Within(Mask, Action<RasterOps>)
Runs the operations build adds, then mixes each pixel with the original by the mask's coverage: none keeps
the original, full keeps the result, and values between blend the two on premultiplied pixels, so a soft mask edge gives a soft
transition. Only the box around the mask's non-zero coverage is touched. Masks nest by multiplying their coverage, and mix
freely with rectangles.
public RasterOps Within(Mask mask, Action<RasterOps> build)
Parameters
maskMaskThe coverage: a raster of any size and type, placed at its offset, read by its channel.
buildAction<RasterOps>Adds the operations. Each must keep the size, as in Within(Rect, Action<RasterOps>).
Returns
- RasterOps
This builder.
Examples
// Edit only the sky: a gray mask, white where the edit applies fully, black where it does not, soft in between.
photo.Apply(ops => ops
.Within(new Mask(sky), o => o.Saturation(1.3f).Contrast(1.1f))
// Or take coverage from a logo's alpha, placed on the photo, and invert the area under it.
.Within(new Mask(logo, new Point(20, 20), MaskChannel.Alpha), o => o.Invert()), Ct);
Remarks
The mask raster must stay undisposed until the chain has run. Masking a raster with itself reads from a copy, made when the step runs.
Exceptions
- ArgumentNullException
buildis null.- ArgumentException
The mask has no raster, or an operation inside would change the size or the color encoding.
- ArgumentOutOfRangeException
The mask's channel is not defined.
Within(Rect, Action<RasterOps>)
Runs the operations build adds so that only pixels inside area change, as if the image were
edited through a rectangular hole. Filters read the real pixels around the area, so a blurred rectangle has no seam and equals
the whole-image blur there; flips and a 180° turn mirror the area itself. Positions inside (DrawImage, FillColor) are the
raster's, as outside. Scopes nest: a rectangle inside a rectangle is their intersection.
public RasterOps Within(Rect area, Action<RasterOps> build)
Parameters
areaRectThe rectangle, in the raster's coordinates. It is clipped to the raster; one that misses it changes nothing.
buildAction<RasterOps>Adds the operations. Each must keep the size: a resize, crop, pad, 90° or free turn, AutoOrient, ConvertColor or ToneMap throws.
Returns
- RasterOps
This builder.
Examples
// Blur a face: only pixels inside the rectangle change, and the blur reads the real pixels around it, so there is no seam.
photo.Apply(ops => ops
.Within(new Rect(200, 120, 160, 120), o => o.Blur(6))
.Within(new Rect(0, 0, photo.Width, 60), o => o.Brightness(0.8f).Saturation(0.5f)), Ct); // a darker band on top
Exceptions
- ArgumentNullException
buildis null.- ArgumentOutOfRangeException
areahas a negative width or height.- ArgumentException
An operation inside would change the size or the color encoding; the message names it.
ZoomBlur(float, Vector2?)
Streaks the image along rays from center, as a zoom during the exposure (Photoshop's radial zoom blur):
each pixel averages samples on the ray through it, spanning amount of its distance from the center, half
inward and half outward, about one per pixel (at most 256). The center does not move, and a flat image stays flat.
public RasterOps ZoomBlur(float amount, Vector2? center = null)
Parameters
amountfloatThe streak's length as a fraction of the distance from the center, from 0 (changes nothing) to 1.
centerVector2?The center in pixels, pixel centers at +0.5, or null for the image's center.
Returns
- RasterOps
This builder.
Examples
using Raster moving = photo.Derive(ops => ops.MotionBlur(radius: 12, sigma: 4, angle: 15), Ct); // a streak toward 15°
using Raster spinning = photo.Derive(ops => ops.RotationalBlur(8), Ct); // 8° around the center
using Raster zooming = photo.Derive(ops => ops.ZoomBlur(0.2f, new System.Numerics.Vector2(320, 200)), Ct);
Exceptions
- ArgumentOutOfRangeException
amountis outside 0..1, or the center is not finite.