ToneCurve Class

An immutable tone curve: a function that gives a new value to a sample value, for ImageProcessingExtensions.ApplyToneCurve and ImageProcessingExtensions.ApplyToneCurves.

public sealed class ToneCurve

Remarks

Values are fractions of the largest sample value: 0 is black and 1 is full intensity, for every pixel format (a level v of an 8-bit sample is v / 255). A curve is made of a gamma correction (ToneCurve.CreateGamma), a levels adjustment (ToneCurve.CreateLevels), a smooth curve through control points (ToneCurve.CreateFromPoints), a one-dimensional lookup table (ToneCurve.CreateFromTable), or a sequence of them (ToneCurve.Then), and ToneCurve.Evaluate gives its value anywhere.

Every function is defined for every number, so that floating-point samples outside [0, 1] (highlights, negative out-of-gamut colors) have a value too: see each factory method. A value that is not a number stays one.

Properties

NameDescription
IdentityGets the curve that keeps every value.
IsIdentityGets a value indicating whether the curve keeps every value: it is ToneCurve.Identity, or a sequence of curves that keep every value.

Identity

ToneCurve.cs

Gets the curve that keeps every value.

public static ToneCurve Identity { get; }

Property value

ToneCurve

IsIdentity

ToneCurve.cs

Gets a value indicating whether the curve keeps every value: it is ToneCurve.Identity, or a sequence of curves that keep every value.

public bool IsIdentity { get; }

Property value

bool

Methods

NameDescription
CreateFromPoints(ReadOnlySpan<PointD>)Creates a smooth curve through control points: the curves of photo editors. Between two points, the curve is the monotone piecewise cubic Hermite interpolation of Fritsch and Carlson (PCHIP): it goes through every point, never overshoots them, and rises (or falls) wherever the points do, so that it never inverts the tones between two points.
CreateFromTable(ReadOnlySpan<double>)Creates a curve from a one-dimensional lookup table: the values of the curve at evenly spaced inputs from 0 to 1, interpolated linearly in between. A table of n values gives value i to the input i / (n - 1).
CreateGamma(double)Creates a gamma correction: a value v becomes v^(1 / gamma), so a gamma above 1 brightens the midtones and a gamma below 1 darkens them, while 0 and 1 are kept. It is the gamma of ImageMagick's -gamma and of the middle slider of the levels of Photoshop and GIMP.
CreateLevels(double, double, double, double, double)Creates a levels adjustment: the values from inputBlack to inputWhite are stretched to [0, 1], clipped, corrected by gamma, and stretched to the range from outputBlack to outputWhite.
Evaluate(double)Gets the value of the curve at a value.
Then(ToneCurve)Gets the curve that applies this one, then another one to its result.

CreateFromPoints(ReadOnlySpan<PointD>)

ToneCurve.cs

Creates a smooth curve through control points: the curves of photo editors. Between two points, the curve is the monotone piecewise cubic Hermite interpolation of Fritsch and Carlson (PCHIP): it goes through every point, never overshoots them, and rises (or falls) wherever the points do, so that it never inverts the tones between two points.

public static ToneCurve CreateFromPoints(params scoped ReadOnlySpan<PointD> points)

Parameters

points ReadOnlySpan<PointD>
At least two points, ordered by increasing PointD.X, with finite coordinates; PointD.X is the input value and PointD.Y the output value. They are copied.

Returns

ToneCurve The curve.

Exceptions

ArgumentException
There are fewer than two points, a coordinate is not finite, or the PointD.X coordinates are not strictly increasing.

Remarks

The slopes at the points are those of SciPy's PchipInterpolator (and of MATLAB's pchip): 0 at a point where the curve changes direction, the weighted harmonic mean of the slopes of the two segments elsewhere, and a three-point estimate at the first and the last point. Two points give a straight line.

Before the first point and after the last one, the curve is flat: it keeps the value of the nearest point, as in Photoshop and GIMP. To clip the shadows, start at (0.1, 0); to keep the whole range, start at (0, 0) and end at (1, 1).

CreateFromTable(ReadOnlySpan<double>)

ToneCurve.cs

Creates a curve from a one-dimensional lookup table: the values of the curve at evenly spaced inputs from 0 to 1, interpolated linearly in between. A table of n values gives value i to the input i / (n - 1).

public static ToneCurve CreateFromTable(params scoped ReadOnlySpan<double> values)

Parameters

values ReadOnlySpan<double>
At least two finite values. They are copied.

Returns

ToneCurve The curve.

Exceptions

ArgumentException
There are fewer than two values, or a value is not finite.

Remarks

Before 0 and after 1, the curve keeps the first and the last value of the table. A table of 256 values applied to an 8-bit sample reads exactly one value per level, without interpolation.

CreateGamma(double)

ToneCurve.cs

Creates a gamma correction: a value v becomes v^(1 / gamma), so a gamma above 1 brightens the midtones and a gamma below 1 darkens them, while 0 and 1 are kept. It is the gamma of ImageMagick's -gamma and of the middle slider of the levels of Photoshop and GIMP.

public static ToneCurve CreateGamma(double gamma)

Parameters

gamma double
The gamma. Must be a positive finite number; 1 gives ToneCurve.Identity.

Returns

ToneCurve The curve.

Exceptions

ArgumentOutOfRangeException
gamma is not a positive finite number.

Remarks

A negative value v becomes -(-v)^(1 / gamma), so the curve is odd and keeps the sign.

CreateLevels(double, double, double, double, double)

ToneCurve.cs

Creates a levels adjustment: the values from inputBlack to inputWhite are stretched to [0, 1], clipped, corrected by gamma, and stretched to the range from outputBlack to outputWhite.

public static ToneCurve CreateLevels(double inputBlack, double inputWhite, double gamma = 1d, double outputBlack = 0d, double outputWhite = 1d)

Parameters

inputBlack double
The value that becomes outputBlack. Must be finite.
inputWhite double
The value that becomes outputWhite. Must be finite and greater than inputBlack.
gamma double
The gamma correction of the midtones, as ToneCurve.CreateGamma. Must be a positive finite number.
outputBlack double
The darkest value of the result. Must be finite.
outputWhite double
The brightest value of the result. Must be finite.

Returns

ToneCurve The curve.

Exceptions

ArgumentException
A value is not finite, or inputWhite is not greater than inputBlack.
ArgumentOutOfRangeException
gamma is not a positive finite number.

Remarks

A value v becomes outputBlack + (outputWhite - outputBlack) * t^(1 / gamma), where t = clamp((v - inputBlack) / (inputWhite - inputBlack), 0, 1): the levels of Photoshop and GIMP, and ImageMagick's -level followed by +level. Every value below inputBlack becomes outputBlack and every value above inputWhite becomes outputWhite, floating-point values outside [0, 1] included: the input range clips. An output black above the output white inverts the values.

Evaluate(double)

ToneCurve.cs

Gets the value of the curve at a value.

public double Evaluate(double value)

Parameters

value double
The value, a fraction of the largest sample value.

Returns

double The value of the curve; Double.NaN when value is not a number.

Then(ToneCurve)

ToneCurve.cs

Gets the curve that applies this one, then another one to its result.

public ToneCurve Then(ToneCurve next)

Parameters

next ToneCurve
The curve applied to the values of this one.

Returns

ToneCurve The combined curve: next.Evaluate(this.Evaluate(v)).

Exceptions

ArgumentNullException
next is null.