diff --git a/src/ImageSharp/Formats/Jxl/Cms/JxlOpsinConstants.cs b/src/ImageSharp/Formats/Jxl/Cms/JxlOpsinConstants.cs
new file mode 100644
index 000000000..a0029c0c2
--- /dev/null
+++ b/src/ImageSharp/Formats/Jxl/Cms/JxlOpsinConstants.cs
@@ -0,0 +1,24 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+namespace SixLabors.ImageSharp.Formats.Jxl.Cms;
+
+///
+/// Opsin constants used by the color management system
+///
+internal static class JxlOpsinConstants
+{
+ public const float BScale = 1f;
+
+ // The following constants are used for XYB.
+ // They can be adjusted to change how Y<->B ratio
+ // works. For example, YToBRatio works better
+ // with 0.50017729543783418.
+ public const float YToBRatio = 1f;
+ public const float BToYRatio = 1f / YToBRatio;
+
+ // Adjusting these constants influences the opsin absorbance.
+ public const float OpsinAbsorbanceBias0 = 0.0037930732552754493f;
+ public const float OpsinAbsorbanceBias1 = OpsinAbsorbanceBias0;
+ public const float OpsinAbsorbanceBias2 = OpsinAbsorbanceBias0;
+}
diff --git a/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlContextMapDecoder.cs b/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlContextMapDecoder.cs
new file mode 100644
index 000000000..78b989910
--- /dev/null
+++ b/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlContextMapDecoder.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder;
+
+public class JxlContextMapDecoder
+{
+
+}
diff --git a/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlXybDecoder.cs b/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlXybDecoder.cs
index 940b01170..7fd7d54c6 100644
--- a/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlXybDecoder.cs
+++ b/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlXybDecoder.cs
@@ -33,9 +33,9 @@ internal static class JxlXybDecoder
ref Vector linearG,
ref Vector linearB)
{
- Vector negBiasR = new(opsinParameters.OpsinBiaases[0]);
- Vector negBiasG = new(opsinParameters.OpsinBiaases[1]);
- Vector negBiasB = new(opsinParameters.OpsinBiaases[2]);
+ Vector negBiasR = new(opsinParameters.OpsinBiases[0]);
+ Vector negBiasG = new(opsinParameters.OpsinBiases[1]);
+ Vector negBiasB = new(opsinParameters.OpsinBiases[2]);
Vector gammaR = opsinX + opsinY;
Vector gammaG = opsinY - opsinX;
@@ -49,7 +49,7 @@ internal static class JxlXybDecoder
Vector mixedG = (gammaG2 * gammaG) + negBiasG;
Vector mixedB = (gammaB2 * gammaB) + negBiasB;
- Span inverseMatrix = opsinParameters.GetInverseOpsinMatrixSpan();
+ Span inverseMatrix = opsinParameters.InverseOpsinMatrix;
linearR = LoadDuplicate128(ref inverseMatrix[0 * 4]) * mixedR;
linearG = LoadDuplicate128(ref inverseMatrix[3 * 4]) * mixedR;
@@ -66,7 +66,7 @@ internal static class JxlXybDecoder
public static bool OpsinToLinear(JxlImage3F opsin, Rectangle rect, JxlImage3F linear, JxlOpsinParameters opsinParameters)
{
- if (!SameSize(rect, linear))
+ if (!JxlImageOperations.SameSize(rect, linear))
{
return false;
}
diff --git a/src/ImageSharp/Formats/Jxl/Processing/Encoder/Ans/JxlHistogram.cs b/src/ImageSharp/Formats/Jxl/Processing/Encoder/Ans/JxlHistogram.cs
index 70a932107..52637c989 100644
--- a/src/ImageSharp/Formats/Jxl/Processing/Encoder/Ans/JxlHistogram.cs
+++ b/src/ImageSharp/Formats/Jxl/Processing/Encoder/Ans/JxlHistogram.cs
@@ -8,11 +8,6 @@ namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Encoder.Ans;
///
internal sealed class JxlHistogram(int length)
{
- ///
- /// Rounding constant
- ///
- private const int Rounding = 8;
-
public List Counts { get; set; } = new(length);
public int TotalCount { get; set; }
diff --git a/src/ImageSharp/Formats/Jxl/Processing/JxlColorCorrelation.cs b/src/ImageSharp/Formats/Jxl/Processing/JxlColorCorrelation.cs
index 69e617ea9..7047c2c7c 100644
--- a/src/ImageSharp/Formats/Jxl/Processing/JxlColorCorrelation.cs
+++ b/src/ImageSharp/Formats/Jxl/Processing/JxlColorCorrelation.cs
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
+using SixLabors.ImageSharp.Formats.Jxl.Cms;
using SixLabors.ImageSharp.Formats.Jxl.Fields;
using SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder;
@@ -9,7 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Jxl.Processing;
internal sealed class JxlColorCorrelation
{
private float baseCorrelationX;
- private float baseCorrelationB = DefaultYToBRatio;
+ private float baseCorrelationB = JxlOpsinConstants.YToBRatio;
private readonly float[] dcFactors = new float[4];
private uint colorFactor = JxlChromaFromLuma.DefaultColorFactor;
diff --git a/src/ImageSharp/Formats/Jxl/Processing/JxlDctAcImage{T}.cs b/src/ImageSharp/Formats/Jxl/Processing/JxlDctAcImage{T}.cs
index 2052daee6..8e74c26b7 100644
--- a/src/ImageSharp/Formats/Jxl/Processing/JxlDctAcImage{T}.cs
+++ b/src/ImageSharp/Formats/Jxl/Processing/JxlDctAcImage{T}.cs
@@ -23,9 +23,9 @@ internal sealed class JxlDctAcImage : IJxlDctAcImage, IDisposable
public bool IsEmpty => this.image.XSize == 0 || this.image.YSize == 0;
- public void Clear() => JxlImageOperations.ClearImage(this.image);
+ public void Clear() => JxlImageOperations.ZeroFillImage(this.image);
- public void Clear(int plane = 0) => JxlImageOperations.ClearImage(this.image);
+ public void Clear(int plane = 0) => JxlImageOperations.ZeroFillImage(this.image);
public unsafe JxlDctAcPointer GetPlaneRow(int channel, int y, int xBase = 0)
{
diff --git a/src/ImageSharp/Formats/Jxl/Processing/JxlLoopFilter.cs b/src/ImageSharp/Formats/Jxl/Processing/JxlLoopFilter.cs
index 312138db4..2df002fba 100644
--- a/src/ImageSharp/Formats/Jxl/Processing/JxlLoopFilter.cs
+++ b/src/ImageSharp/Formats/Jxl/Processing/JxlLoopFilter.cs
@@ -4,6 +4,7 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Jxl.Fields;
+using SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder;
namespace SixLabors.ImageSharp.Formats.Jxl.Processing;
@@ -181,13 +182,13 @@ internal sealed class JxlLoopFilter : IJxlFields
JxlAcStrategyImage acStrategy = state.Shared.AcStrategy;
float quantScale = state.Shared.Quantizer.Scale;
- int sigmaStride = state.Sigma.PixelsPerRow;
+ int sigmaStride = state.Sigma!.PixelsPerRow;
int sharpnessStride = state.Shared.EpfSharpness.PixelsPerRow;
for (int by = 0; by < blockRect.Height; by++)
{
- Span sigmaRow = state.Sigma.GetRowSpan(by);
- Span sharpnessRow = state.Shared.EpfSharpness.GetRowSpan(by);
+ Span sigmaRow = state.Sigma.GetRow(by);
+ Span sharpnessRow = state.Shared.EpfSharpness.GetRow(by);
JxlAcStrategyRow acsRow = acStrategy.GetRow(in blockRect, by);
Span rowQuant = state.Shared.RawQuantField.GetRow(by);
@@ -245,7 +246,7 @@ internal sealed class JxlLoopFilter : IJxlFields
}
}
- if (by + blockRect.Y + acs.CoveredBlocksX == state.Shared.FrameDimensions.YSizeBloks)
+ if (by + blockRect.Y + acs.CoveredBlocksX == state.Shared.FrameDimensions.YSizeBlocks)
{
for (int iy = 0; iy < SigmaBorder; iy++)
{
diff --git a/src/ImageSharp/Formats/Jxl/Processing/JxlWeightsSeparable5.cs b/src/ImageSharp/Formats/Jxl/Processing/JxlWeightsSeparable5.cs
index 7fdec43b0..b2a0c0c55 100644
--- a/src/ImageSharp/Formats/Jxl/Processing/JxlWeightsSeparable5.cs
+++ b/src/ImageSharp/Formats/Jxl/Processing/JxlWeightsSeparable5.cs
@@ -6,7 +6,6 @@ namespace SixLabors.ImageSharp.Formats.Jxl.Processing;
internal struct JxlWeightsSeparable5
{
// Don't make these a property so we can ref into them.
-
public InlineArray12 Horizontal;
public InlineArray12 Vertical;
diff --git a/src/ImageSharp/Formats/Jxl/Processing/Modular/Encoding/ContextPrediction/JxlModularState.cs b/src/ImageSharp/Formats/Jxl/Processing/Modular/Encoding/ContextPrediction/JxlModularState.cs
index e58897b4f..f731dc967 100644
--- a/src/ImageSharp/Formats/Jxl/Processing/Modular/Encoding/ContextPrediction/JxlModularState.cs
+++ b/src/ImageSharp/Formats/Jxl/Processing/Modular/Encoding/ContextPrediction/JxlModularState.cs
@@ -21,7 +21,7 @@ internal sealed class JxlModularState
private readonly int[] error;
private readonly JxlModularHeader header;
- public JxlModularState(JxlModularHeader header, int width, int height)
+ public JxlModularState(JxlModularHeader header, int width)
{
this.header = header;
@@ -104,9 +104,9 @@ internal sealed class JxlModularState
int cur_row = yIsOdd ? 0 : (width + 2);
int prev_row = yIsOdd ? (width + 2) : 0;
- int pos_N = prev_row + x;
- int pos_NE = x < width - 1 ? pos_N + 1 : pos_N;
- int pos_NW = x > 0 ? pos_N - 1 : pos_N;
+ int posN = prev_row + x;
+ int posNE = x < width - 1 ? posN + 1 : posN;
+ int posNW = x > 0 ? posN - 1 : posN;
Span weights = stackalloc uint[4];
ref uint headerW = ref this.header.GetWReference();
@@ -114,7 +114,7 @@ internal sealed class JxlModularState
for (int i = 0; i < 4; i++)
{
Span error = this.predErrors[i].AsSpan();
- weights[i] = error[pos_N] + error[pos_NE] + error[pos_NW];
+ weights[i] = error[posN] + error[posNE] + error[posNW];
weights[i] = ErrorWeight((int)weights[i], Unsafe.Add(ref headerW, i));
}
@@ -125,10 +125,10 @@ internal sealed class JxlModularState
nn = AddBits(nn);
long teW = x == 0 ? 0 : this.error[cur_row + x - 1];
- long teN = this.error[pos_N];
- long teNW = this.error[pos_NW];
+ long teN = this.error[posN];
+ long teNW = this.error[posNW];
long sumWN = teN + teW;
- long teNE = this.error[pos_NE];
+ long teNE = this.error[posNE];
if (computeProperties)
{
diff --git a/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlQuantizedSpline.cs b/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlQuantizedSpline.cs
index 7e46f49b0..731c22835 100644
--- a/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlQuantizedSpline.cs
+++ b/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlQuantizedSpline.cs
@@ -50,10 +50,11 @@ internal sealed class JxlQuantizedSpline : IDisposable
public static JxlQuantizedSpline Create(Configuration configuration, JxlSpline original, int quantizationAdjustment, float yToX, float yToB)
{
JxlQuantizedSpline spline = new();
+ Span controlPoints = original.ControlPoints.Span;
- spline.ReserveControlPoints(configuration, original.ControlPoints.Count - 1);
+ spline.ReserveControlPoints(configuration, controlPoints.Length - 1);
- PointF startingPoint = original.ControlPoints.First();
+ PointF startingPoint = controlPoints[0];
int previousX = (int)MathF.Round(startingPoint.X);
int previousY = (int)MathF.Round(startingPoint.Y);
int previousDx = 0; // D stands for delta
@@ -65,7 +66,7 @@ internal sealed class JxlQuantizedSpline : IDisposable
for (int i = 0; i < length; i++)
{
- PointF controlPoint = original.ControlPoints[i];
+ PointF controlPoint = controlPoints[i];
int newX = (int)MathF.Round(controlPoint.X);
int newY = (int)MathF.Round(controlPoint.Y);
@@ -93,8 +94,8 @@ internal sealed class JxlQuantizedSpline : IDisposable
// for i=0 and adding a separate loop for i=1..31
for (int i = 0; i < 32; i++)
{
- float dctFactor = (i == 0) ? Sqrt2 : 1.0f;
- float inverseDctFactor = (i == 0) ? Sqrt05 : 1.0f;
+ float dctFactor = (i == 0) ? JxlDctScales.Sqrt2 : 1.0f;
+ float inverseDctFactor = (i == 0) ? JxlDctScales.Sqrt05 : 1.0f;
float restoredY = spline.ColorDct[1][i] * inverseDctFactor * ChannelWeight[1] * inverseQuant;
float decorrelated = spline.ColorDct[c][i] - (factor * restoredY);
spline.ColorDct[c][i] = ConvertToInteger(decorrelated * dctFactor * quant / ChannelWeight[c]);
@@ -103,7 +104,7 @@ internal sealed class JxlQuantizedSpline : IDisposable
for (int i = 0; i < 32; i++)
{
- float dctFactor = (i == 0) ? Sqrt2 : 1.0f;
+ float dctFactor = (i == 0) ? JxlDctScales.Sqrt2 : 1.0f;
spline.SigmaDct[i] = ConvertToInteger(original.SigmaDct[i] * dctFactor * quant / ChannelWeight[1]);
}
@@ -190,7 +191,7 @@ internal sealed class JxlQuantizedSpline : IDisposable
{
for (int i = 0; i < 32; i++)
{
- float inverseDctFactor = (i == 0) ? Sqrt05 : 1.0f;
+ float inverseDctFactor = (i == 0) ? JxlDctScales.Sqrt05 : 1.0f;
result.ColorDct[c][i] = this.ColorDct[c][i] * inverseDctFactor * ChannelWeight[c] * inverseQuant;
}
}