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; } }