mirror of https://github.com/SixLabors/ImageSharp
7 changed files with 249 additions and 4 deletions
@ -0,0 +1,20 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Jxl.Cms.TransferFunctions; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// ITU-R BT.709 transfer function
|
||||
|
/// </summary>
|
||||
|
internal static class JxlBt709TransferFunction |
||||
|
{ |
||||
|
public static double EncodedFromDisplay(double d) |
||||
|
{ |
||||
|
if (d < Threshold) |
||||
|
{ |
||||
|
return MulLow * d; |
||||
|
} |
||||
|
|
||||
|
return (MulHi * Math.Pow(d, PowHi)) + Sub; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,53 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
using System.Numerics; |
||||
|
using SixLabors.ImageSharp.Formats.Jxl.Processing; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Jxl.Cms.TransferFunctions; |
||||
|
|
||||
|
internal sealed class JxlHybridLogGammaTransferFunction : JxlHybridLogGammaTransferFunctionBase |
||||
|
{ |
||||
|
private const float HiAdd = B * Inverse12; |
||||
|
private const float HiMul = 0.003639807079052639f; // MathF.Exp(-C * RA) * Inverse12
|
||||
|
private const float HiPow = 8.067285659607931f; // RA * JxlMath.InverseLog2E
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="JxlHybridLogGammaTransferFunction"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// Use static methods. Don't instantiate this class.
|
||||
|
/// </remarks>
|
||||
|
private JxlHybridLogGammaTransferFunction() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public static Vector<float> EncodedFromDisplay(Vector<float> x) |
||||
|
{ |
||||
|
Vector<float> sign = Vector.Create(0x80000000u).As<uint, float>(); |
||||
|
Vector<float> originalSign = x & sign; |
||||
|
x = Vector.AndNot(sign, x); |
||||
|
Vector<int> belowInverse12 = Vector.LessThan(x, Vector.Create(Inverse12)); |
||||
|
|
||||
|
Vector<float> lo = Vector.SquareRoot(Vector.Create(3.0f) * x); |
||||
|
Vector<float> hi = (Vector.Create(A * JxlMath.InverseLog2E) * Vector.Log2((Vector.Create(12f) * x) + Vector.Create(-B))) + Vector.Create(C); |
||||
|
Vector<float> magnitude = Vector.ConditionalSelect(belowInverse12, lo, hi); |
||||
|
return Vector.AndNot(sign, magnitude) | originalSign; |
||||
|
} |
||||
|
|
||||
|
public static Vector<float> DisplayFromEncoded(Vector<float> x) |
||||
|
{ |
||||
|
Vector<float> sign = Vector.Create(0x80000000u).As<uint, float>(); |
||||
|
Vector<float> originalSign = x & sign; |
||||
|
x = Vector.AndNot(sign, x); |
||||
|
Vector<int> below05 = Vector.LessThan(x, Vector.Create(0.5f)); |
||||
|
|
||||
|
Vector<float> lo = x * (x * Vector.Create(1f / 3f)); |
||||
|
Vector<float> hi = (Pow2(x * Vector.Create(HiPow)) * Vector.Create(HiMul)) + Vector.Create(HiAdd); |
||||
|
Vector<float> magnitude = Vector.ConditionalSelect(below05, lo, hi); |
||||
|
|
||||
|
return Vector.AndNot(sign, magnitude) | originalSign; |
||||
|
} |
||||
|
|
||||
|
private static Vector<float> Pow2(Vector<float> x) => x * x; |
||||
|
} |
||||
@ -0,0 +1,114 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Jxl.Cms.TransferFunctions; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Base class for HLG transfer function.
|
||||
|
/// </summary>
|
||||
|
internal abstract class JxlHybridLogGammaTransferFunctionBase |
||||
|
{ |
||||
|
// Shared constants used by transfer functions
|
||||
|
protected const float A = 0.17883277f; |
||||
|
protected const float RA = 1.0f / A; |
||||
|
protected const float B = 1 - (4 * A); |
||||
|
protected const float C = 0.5599107295f; |
||||
|
protected const float Inverse12 = 1.0f / 12.0f; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Converts encoded signal to display signal.
|
||||
|
/// </summary>
|
||||
|
/// <param name="encoded">The encoded signal</param>
|
||||
|
/// <returns>The display signal</returns>
|
||||
|
protected static double DisplayFromEncoded(double encoded) => Ootf(InverseOotf(encoded)); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Converts display signal to encoded signal.
|
||||
|
/// </summary>
|
||||
|
/// <param name="display">The display signal</param>
|
||||
|
/// <returns>The encoded signal</returns>
|
||||
|
protected static double EncodedFromDisplay(double display) => Oetf(InverseOetf(display)); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Opto-Electronic Transfer Function - converts
|
||||
|
/// real-world scene light (s) into a digital video
|
||||
|
/// signal inside a camera.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// <seealso href="https://en.wikipedia.org/wiki/Transfer_functions_in_imaging#Definition"/>
|
||||
|
/// </remarks>
|
||||
|
/// <param name="s">Scene light</param>
|
||||
|
/// <returns>Digital video signal</returns>
|
||||
|
private static double Oetf(double s) |
||||
|
{ |
||||
|
if (s == 0) |
||||
|
{ |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
double originalSign = s; |
||||
|
|
||||
|
s = Math.Abs(s); |
||||
|
|
||||
|
if (s <= Inverse12) |
||||
|
{ |
||||
|
return Math.CopySign(Math.Sqrt(3.0 * s), originalSign); |
||||
|
} |
||||
|
|
||||
|
double e = (A * Math.Log((12 * s) - B)) + C; |
||||
|
DebugGuard.MustBeGreaterThan(e, 0.0, nameof(e)); |
||||
|
|
||||
|
return Math.CopySign(e, originalSign); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Inverse Opto-Electronic Transfer Function - converts
|
||||
|
/// digital video signal into a real-world scene light.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// <seealso href="https://en.wikipedia.org/wiki/Transfer_functions_in_imaging#Definition"/>
|
||||
|
/// </remarks>
|
||||
|
/// <param name="e">Digital video signal</param>
|
||||
|
/// <returns>Scene light</returns>
|
||||
|
private static double InverseOetf(double e) |
||||
|
{ |
||||
|
if (e == 0) |
||||
|
{ |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
double originalSign = e; |
||||
|
|
||||
|
e = Math.Abs(e); |
||||
|
|
||||
|
if (e <= 0.5) |
||||
|
{ |
||||
|
return Math.CopySign(e * e * (1.0 / 3), originalSign); |
||||
|
} |
||||
|
|
||||
|
double s = (Math.Exp((e - C) * RA) + B) * Inverse12; |
||||
|
DebugGuard.MustBeGreaterThan(s, 0.0, nameof(s)); |
||||
|
|
||||
|
return Math.CopySign(s, originalSign); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Opto-Optical Transfer Function - as-is.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// <seealso href="https://en.wikipedia.org/wiki/Transfer_functions_in_imaging#Definition"/>
|
||||
|
/// </remarks>
|
||||
|
/// <param name="s">Input signal</param>
|
||||
|
/// <returns>Digital video signal</returns>
|
||||
|
private static double Ootf(double s) => s; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Inverse Opto-Optical Transfer Function - as-is.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// <seealso href="https://en.wikipedia.org/wiki/Transfer_functions_in_imaging#Definition"/>
|
||||
|
/// </remarks>
|
||||
|
/// <param name="s">Digital video signal</param>
|
||||
|
/// <returns>Scene light</returns>
|
||||
|
private static double InverseOotf(double s) => s; |
||||
|
} |
||||
@ -0,0 +1,54 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Jxl.Cms.TransferFunctions; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Base class for PQ transfer function.
|
||||
|
/// </summary>
|
||||
|
internal abstract class JxlPerceptualQuantizationTransferFunctionBase |
||||
|
{ |
||||
|
private const double M1 = 2610.0 / 16384; |
||||
|
private const double M2 = (2523.0 / 4096) * 128; |
||||
|
private const double C1 = 3424.0 / 4096; |
||||
|
private const double C2 = (2413.0 / 4096) * 32; |
||||
|
private const double C3 = (2392.0 / 4096) * 32; |
||||
|
|
||||
|
protected static double DisplayFromEncoded(float displayIntensityTarget, double e) |
||||
|
{ |
||||
|
if (e == 0.0) |
||||
|
{ |
||||
|
return 0.0; |
||||
|
} |
||||
|
|
||||
|
double originalSign = e; |
||||
|
|
||||
|
e = Math.Abs(e); |
||||
|
|
||||
|
double xp = Math.Pow(e, 1.0 / M2); |
||||
|
double num = Math.Max(xp - C1, 0.0); |
||||
|
double den = C2 - (C3 * xp); |
||||
|
double d = Math.Pow(num / den, 1.0 / M1); |
||||
|
|
||||
|
return Math.CopySign(d * (10000.0 / displayIntensityTarget), originalSign); |
||||
|
} |
||||
|
|
||||
|
protected static double EncodedFromDisplay(float displayIntensityTarget, double d) |
||||
|
{ |
||||
|
if (d == 0.0) |
||||
|
{ |
||||
|
return 0.0; |
||||
|
} |
||||
|
|
||||
|
double originalSign = d; |
||||
|
|
||||
|
d = Math.Abs(d); |
||||
|
|
||||
|
double xp = Math.Pow(d * (displayIntensityTarget * (1 / 10000)), M1); |
||||
|
double num = C1 + (xp * C2); |
||||
|
double den = 1.0 + (xp * C3); |
||||
|
double e = Math.Pow(num / den, M2); |
||||
|
|
||||
|
return Math.CopySign(e, originalSign); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue