diff --git a/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlGroupDecoderCache.cs b/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlGroupDecoderCache.cs
new file mode 100644
index 000000000..f82e332d8
--- /dev/null
+++ b/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlGroupDecoderCache.cs
@@ -0,0 +1,12 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder;
+
+///
+/// Cache for the JPEG XL Group Decoder.
+///
+internal sealed class JxlGroupDecoderCache
+{
+
+}
diff --git a/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlPassesDecoderState.cs b/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlPassesDecoderState.cs
new file mode 100644
index 000000000..5b534ef77
--- /dev/null
+++ b/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlPassesDecoderState.cs
@@ -0,0 +1,77 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+using SixLabors.ImageSharp.Formats.Jxl.IO.FrameHeader;
+using SixLabors.ImageSharp.Formats.Jxl.Memory.ImageTypes;
+
+namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder;
+
+internal sealed class JxlPassesDecoderState
+{
+ public JxlPassesDecoderState(JxlFrameHeader header, Configuration configuration)
+ {
+ this.XDmMultiplier = MathF.Pow(1 / 1.25f, header.XQmScale - 2f);
+ this.BDmMultiplier = MathF.Pow(1 / 1.25f, header.BQmScale - 2f);
+
+ this.MainOutput.Callback = PixelCallback;
+ this.MainOutput.Buffer = null;
+
+ this.UndoOrientation = JxlOrientation.Identity;
+ this.Upsampler8x = GetUpsamplingImage(configuration, this.Shared.CodecMetadata.CustomTransformData, 0, 3);
+
+ if (header.LoopFilter?.EpfIterations > 0)
+ {
+ this.Sigma = new JxlImageF(
+ configuration,
+ (this.Shared.FrameDimensions.XSizeBlocks + 2) * SigmaPadding,
+ (this.Shared.FrameDimensions.YSizeBlocks + 2) * SigmaPadding);
+ }
+
+ this.SharedStorage = new(configuration, header, false);
+ this.Shared = this.SharedStorage;
+ }
+
+ public JxlPassesSharedState SharedStorage { get; set; }
+
+ public JxlPassesSharedState Shared { get; set; }
+
+ public JxlRenderPipelineStage[] Upsampler8x { get; set; } = [];
+
+ public List Code { get; set; } = [];
+
+ public List> ContextMap { get; set; } = [];
+
+ public float XDmMultiplier { get; set; }
+
+ public float BDmMultiplier { get; set; }
+
+ public JxlImageF? Sigma { get; set; }
+
+ public int Width { get; set; }
+
+ public int Height { get; set; }
+
+ public JxlImageOutput MainOutput { get; set; }
+
+ public List ExtraOutput { get; set; } = [];
+
+ public bool FastXybSRgb8Conversion { get; set; }
+
+ public bool UnpremultiplyAlpha { get; set; }
+
+ public JxlOrientation UndoOrientation { get; set; }
+
+ public int VisibleFrameIndex { get; set; }
+
+ public int NonvisibleFrameIndex { get; set; }
+
+ public int UsedAcs { get; set; }
+
+ public JxlDctAcImage Coefficients { get; set; } = [];
+
+ public JxlRenderPipeline RenderPipeline { get; set; }
+
+ public JxlImageBundle FrameStorageForReferencing { get; set; }
+
+ public JxlOutputEncodingInfo OutputEncodingInfo { get; set; } = new();
+}
diff --git a/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlQuantizedSpline.cs b/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlQuantizedSpline.cs
index ed5729067..40dff40e2 100644
--- a/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlQuantizedSpline.cs
+++ b/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlQuantizedSpline.cs
@@ -3,6 +3,7 @@
using System.Buffers;
using System.Runtime.CompilerServices;
+using SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder;
namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Splines;
@@ -269,8 +270,8 @@ internal sealed class JxlQuantizedSpline : IDisposable
{
ref JxlControlPoint controlPoint = ref controlPoints[i];
- controlPoint.First = UnpackSigned(decoder.ReadHybridUnsignedInteger(ControlPointsContext, br, contextMap));
- controlPoint.Second = UnpackSigned(decoder.ReadHybridUnsignedInteger(ControlPointsContext, br, contextMap));
+ controlPoint.First = JxlPackSigned.UnpackSigned(decoder.ReadHybridUnsignedInteger(ControlPointsContext, br, contextMap));
+ controlPoint.Second = JxlPackSigned.UnpackSigned(decoder.ReadHybridUnsignedInteger(ControlPointsContext, br, contextMap));
if (controlPoint.First >= deltaLimit || controlPoint.First <= -deltaLimit ||
controlPoint.Second >= deltaLimit || controlPoint.Second <= -deltaLimit)
@@ -300,7 +301,7 @@ internal sealed class JxlQuantizedSpline : IDisposable
for (int i = 0; i < 32; i++)
{
- dct[i] = UnpackSigned(decoder.ReadHybridUnsignedInteger(DctContext, br, contextMap));
+ dct[i] = JxlPackSigned.UnpackSigned(decoder.ReadHybridUnsignedInteger(DctContext, br, contextMap));
if (dct[i] == invalidCoefficient)
{
throw new InvalidOperationException("The DCT coefficient is invalid");