diff --git a/src/ImageSharp/Formats/Jxl/Fields/JxlU32Coder.cs b/src/ImageSharp/Formats/Jxl/Fields/JxlU32Coder.cs index e909f7f74..b097311ab 100644 --- a/src/ImageSharp/Formats/Jxl/Fields/JxlU32Coder.cs +++ b/src/ImageSharp/Formats/Jxl/Fields/JxlU32Coder.cs @@ -2,7 +2,7 @@ // Licensed under the Six Labors Split License. using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats.Jxl.IO; +using SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder; namespace SixLabors.ImageSharp.Formats.Jxl.Fields; diff --git a/src/ImageSharp/Formats/Jxl/IO/JxlAnsConstants.cs b/src/ImageSharp/Formats/Jxl/IO/Entropy/JxlAnsConstants.cs similarity index 89% rename from src/ImageSharp/Formats/Jxl/IO/JxlAnsConstants.cs rename to src/ImageSharp/Formats/Jxl/IO/Entropy/JxlAnsConstants.cs index dcd244ac7..d9b6d1150 100644 --- a/src/ImageSharp/Formats/Jxl/IO/JxlAnsConstants.cs +++ b/src/ImageSharp/Formats/Jxl/IO/Entropy/JxlAnsConstants.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -namespace SixLabors.ImageSharp.Formats.Jxl.IO; +namespace SixLabors.ImageSharp.Formats.Jxl.IO.Entropy; internal static class JxlAnsConstants { diff --git a/src/ImageSharp/Formats/Jxl/IO/JxlAnsEntry.cs b/src/ImageSharp/Formats/Jxl/IO/Entropy/JxlAnsEntry.cs similarity index 86% rename from src/ImageSharp/Formats/Jxl/IO/JxlAnsEntry.cs rename to src/ImageSharp/Formats/Jxl/IO/Entropy/JxlAnsEntry.cs index 25a9d1260..7ec8c7cd4 100644 --- a/src/ImageSharp/Formats/Jxl/IO/JxlAnsEntry.cs +++ b/src/ImageSharp/Formats/Jxl/IO/Entropy/JxlAnsEntry.cs @@ -3,7 +3,7 @@ using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.Formats.Jxl.IO; +namespace SixLabors.ImageSharp.Formats.Jxl.IO.Entropy; [StructLayout(LayoutKind.Sequential)] internal struct JxlAnsEntry diff --git a/src/ImageSharp/Formats/Jxl/IO/JxlAnsHelper.cs b/src/ImageSharp/Formats/Jxl/IO/Entropy/JxlAnsHelper.cs similarity index 99% rename from src/ImageSharp/Formats/Jxl/IO/JxlAnsHelper.cs rename to src/ImageSharp/Formats/Jxl/IO/Entropy/JxlAnsHelper.cs index 35630eb10..8e775050e 100644 --- a/src/ImageSharp/Formats/Jxl/IO/JxlAnsHelper.cs +++ b/src/ImageSharp/Formats/Jxl/IO/Entropy/JxlAnsHelper.cs @@ -5,7 +5,7 @@ using System.Buffers; using System.Diagnostics; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.Formats.Jxl.IO; +namespace SixLabors.ImageSharp.Formats.Jxl.IO.Entropy; internal static class JxlAnsHelper { diff --git a/src/ImageSharp/Formats/Jxl/IO/JxlAnsHybridUIntConfiguration.cs b/src/ImageSharp/Formats/Jxl/IO/Entropy/JxlAnsHybridUIntConfiguration.cs similarity index 97% rename from src/ImageSharp/Formats/Jxl/IO/JxlAnsHybridUIntConfiguration.cs rename to src/ImageSharp/Formats/Jxl/IO/Entropy/JxlAnsHybridUIntConfiguration.cs index 422eb2323..b8609f916 100644 --- a/src/ImageSharp/Formats/Jxl/IO/JxlAnsHybridUIntConfiguration.cs +++ b/src/ImageSharp/Formats/Jxl/IO/Entropy/JxlAnsHybridUIntConfiguration.cs @@ -4,7 +4,7 @@ using System.Diagnostics; using SixLabors.ImageSharp.Formats.Jxl.Fields; -namespace SixLabors.ImageSharp.Formats.Jxl.IO; +namespace SixLabors.ImageSharp.Formats.Jxl.IO.Entropy; internal sealed class JxlAnsHybridUIntConfiguration : IJxlFields { diff --git a/src/ImageSharp/Formats/Jxl/IO/JxlAnsLz77Parameters.cs b/src/ImageSharp/Formats/Jxl/IO/Entropy/JxlAnsLz77Parameters.cs similarity index 90% rename from src/ImageSharp/Formats/Jxl/IO/JxlAnsLz77Parameters.cs rename to src/ImageSharp/Formats/Jxl/IO/Entropy/JxlAnsLz77Parameters.cs index ecf5cdc3f..cbf6d3a4e 100644 --- a/src/ImageSharp/Formats/Jxl/IO/JxlAnsLz77Parameters.cs +++ b/src/ImageSharp/Formats/Jxl/IO/Entropy/JxlAnsLz77Parameters.cs @@ -3,7 +3,7 @@ using SixLabors.ImageSharp.Formats.Jxl.Fields; -namespace SixLabors.ImageSharp.Formats.Jxl.IO; +namespace SixLabors.ImageSharp.Formats.Jxl.IO.Entropy; internal sealed class JxlAnsLz77Parameters : IJxlFields { diff --git a/src/ImageSharp/Formats/Jxl/IO/JxlAnsSymbol.cs b/src/ImageSharp/Formats/Jxl/IO/Entropy/JxlAnsSymbol.cs similarity index 85% rename from src/ImageSharp/Formats/Jxl/IO/JxlAnsSymbol.cs rename to src/ImageSharp/Formats/Jxl/IO/Entropy/JxlAnsSymbol.cs index 75afa94d9..240b2463e 100644 --- a/src/ImageSharp/Formats/Jxl/IO/JxlAnsSymbol.cs +++ b/src/ImageSharp/Formats/Jxl/IO/Entropy/JxlAnsSymbol.cs @@ -3,7 +3,7 @@ using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.Formats.Jxl.IO; +namespace SixLabors.ImageSharp.Formats.Jxl.IO.Entropy; [StructLayout(LayoutKind.Sequential)] internal struct JxlAnsSymbol(int value, int offset, int frequency) diff --git a/src/ImageSharp/Formats/Jxl/IO/FrameHeader/JxlFrameHeader.cs b/src/ImageSharp/Formats/Jxl/IO/FrameHeader/JxlFrameHeader.cs index a45c0e471..43d704504 100644 --- a/src/ImageSharp/Formats/Jxl/IO/FrameHeader/JxlFrameHeader.cs +++ b/src/ImageSharp/Formats/Jxl/IO/FrameHeader/JxlFrameHeader.cs @@ -7,7 +7,7 @@ #pragma warning disable IDE0032 // Use auto property using SixLabors.ImageSharp.Formats.Jxl.Fields; -using SixLabors.ImageSharp.Formats.Jxl.Metadata; +using SixLabors.ImageSharp.Formats.Jxl.IO.Metadata; using SixLabors.ImageSharp.Formats.Jxl.Processing; namespace SixLabors.ImageSharp.Formats.Jxl.IO.FrameHeader; diff --git a/src/ImageSharp/Formats/Jxl/IO/JxlHuffman.cs b/src/ImageSharp/Formats/Jxl/IO/JxlHuffman.cs new file mode 100644 index 000000000..640f66740 --- /dev/null +++ b/src/ImageSharp/Formats/Jxl/IO/JxlHuffman.cs @@ -0,0 +1,9 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats.Jxl.IO; + +internal static class JxlHuffman +{ + +} diff --git a/src/ImageSharp/Formats/Jxl/IO/JxlHuffmanCode.cs b/src/ImageSharp/Formats/Jxl/IO/JxlHuffmanCode.cs new file mode 100644 index 000000000..30bca3446 --- /dev/null +++ b/src/ImageSharp/Formats/Jxl/IO/JxlHuffmanCode.cs @@ -0,0 +1,20 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats.Jxl.IO; + +/// +/// A single Huffman code. +/// +internal struct JxlHuffmanCode +{ + /// + /// Number of bits for this symbol. + /// + public byte Bits; + + /// + /// Symbol value/offset. + /// + public ushort Value; +} diff --git a/src/ImageSharp/Formats/Jxl/IO/JxlAnsReader.cs b/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlAnsReader.cs similarity index 98% rename from src/ImageSharp/Formats/Jxl/IO/JxlAnsReader.cs rename to src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlAnsReader.cs index d28e98c02..5320f5f17 100644 --- a/src/ImageSharp/Formats/Jxl/IO/JxlAnsReader.cs +++ b/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlAnsReader.cs @@ -3,8 +3,9 @@ using System.Buffers; using System.Diagnostics; +using SixLabors.ImageSharp.Formats.Jxl.IO; -namespace SixLabors.ImageSharp.Formats.Jxl.IO; +namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder; internal static class JxlAnsReader { diff --git a/src/ImageSharp/Formats/Jxl/IO/JxlBitReader.cs b/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlBitReader.cs similarity index 98% rename from src/ImageSharp/Formats/Jxl/IO/JxlBitReader.cs rename to src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlBitReader.cs index 50753321e..87c1408f8 100644 --- a/src/ImageSharp/Formats/Jxl/IO/JxlBitReader.cs +++ b/src/ImageSharp/Formats/Jxl/Processing/Decoder/JxlBitReader.cs @@ -4,7 +4,7 @@ using System.Buffers.Binary; using System.Diagnostics; -namespace SixLabors.ImageSharp.Formats.Jxl.IO; +namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder; /// /// Represents a bitstream reader. diff --git a/src/ImageSharp/Formats/Jxl/JxlAspectRatioHelpers.cs b/src/ImageSharp/Formats/Jxl/Processing/JxlAspectRatioHelpers.cs similarity index 94% rename from src/ImageSharp/Formats/Jxl/JxlAspectRatioHelpers.cs rename to src/ImageSharp/Formats/Jxl/Processing/JxlAspectRatioHelpers.cs index ee5d1c134..7fcda36c9 100644 --- a/src/ImageSharp/Formats/Jxl/JxlAspectRatioHelpers.cs +++ b/src/ImageSharp/Formats/Jxl/Processing/JxlAspectRatioHelpers.cs @@ -3,7 +3,7 @@ using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.Formats.Jxl; +namespace SixLabors.ImageSharp.Formats.Jxl.Processing; internal static class JxlAspectRatioHelpers { diff --git a/src/ImageSharp/Formats/Jxl/Processing/JxlBlockContextMap.cs b/src/ImageSharp/Formats/Jxl/Processing/JxlBlockContextMap.cs index 2642a2295..92dd8d94d 100644 --- a/src/ImageSharp/Formats/Jxl/Processing/JxlBlockContextMap.cs +++ b/src/ImageSharp/Formats/Jxl/Processing/JxlBlockContextMap.cs @@ -23,9 +23,9 @@ internal sealed class JxlBlockContextMap public List[] DcThresholds { get; } = [[], [], []]; - public List QfThresholds { get; } = []; + public List QfThresholds { get; set; } = []; - public byte[] ContextMap { get; } = new byte[DefaultContextMap.Length]; + public byte[] ContextMap { get; set; } = new byte[DefaultContextMap.Length]; public int ContextCount { get; set; } diff --git a/src/ImageSharp/Formats/Jxl/Processing/JxlEntropyCoder.cs b/src/ImageSharp/Formats/Jxl/Processing/JxlEntropyCoder.cs new file mode 100644 index 000000000..1b896638c --- /dev/null +++ b/src/ImageSharp/Formats/Jxl/Processing/JxlEntropyCoder.cs @@ -0,0 +1,120 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Formats.Jxl.Fields; +using SixLabors.ImageSharp.Formats.Jxl.Processing.Decoder; + +namespace SixLabors.ImageSharp.Formats.Jxl.Processing; + +/// +/// Helper functions for use in entropy coding. +/// +internal static class JxlEntropyCoder +{ + /// + /// Global DC threshold distributions + /// + public static readonly JxlU32Enc DcThresholdDistributions = new( + JxlFieldExpressions.Bits(4), + JxlFieldExpressions.BitsOffset(8, 16), + JxlFieldExpressions.BitsOffset(16, 272), + JxlFieldExpressions.BitsOffset(32, 65808)); + + /// + /// Global QF threshold distributions + /// + public static readonly JxlU32Enc QfThresholdDistributions = new( + JxlFieldExpressions.Bits(2), + JxlFieldExpressions.BitsOffset(3, 4), + JxlFieldExpressions.BitsOffset(5, 12), + JxlFieldExpressions.BitsOffset(8, 44)); + + /// + /// Predicts the entropy symbol using top and left neighboring pixels. + /// + /// Above row; set to if missing + /// Current row + /// The x coordinate offset + /// Default value that's used if both current and above row cannot be used + /// The predicted coefficient using neighboring pixels. + public static int PredictFromTopAndLeft( + ReadOnlySpan rowTop, + ReadOnlySpan row, + int x, + int defaultValue) + { + if (x == 0) + { + return rowTop.Length == 0 ? defaultValue : rowTop[x]; + } + + if (rowTop.Length == 0) + { + return row[x - 1]; + } + + return (rowTop[x] + rowTop[x - 1] + 1) / 2; + } + + public static bool DecodeBlockContextMap(Configuration configuration, JxlBitReader reader, ref JxlBlockContextMap contextMap) + { + List[] dct = contextMap.DcThresholds; + byte[] ctxMap = contextMap.ContextMap; + + bool isDefaultContextMap = reader.ReadBoolean(); + + if (isDefaultContextMap) + { + contextMap = new(); + return true; + } + + contextMap.DcContextCount = 1; + + for (int j = 0; j <= 2; j++) + { + int dcThresholdCount = (int)reader.ReadBits32(4u); + + dct[j] = new List(dcThresholdCount); + + contextMap.DcContextCount = dcThresholdCount + 1; + + for (int i = 0; i < dcThresholdCount; i++) + { + dct[j][i] = JxlPackSigned.UnpackSigned(JxlU32Coder.Read(DcThresholdDistributions, reader)); + } + } + + int qfThresholdCount = (int)reader.ReadBits32(4u); + + List qft = new(qfThresholdCount); + + for (int i = 0; i < qfThresholdCount; i++) + { + qft[i] = JxlU32Coder.Read(QfThresholdDistributions, reader) + 1; + } + + contextMap.QfThresholds = qft; + + if (contextMap.DcContextCount * qft.Count > 64) + { + throw new InvalidOperationException("Invalid block context map. It is too large."); + } + + Array.Resize(ref ctxMap, 3 * JxlForwardCoefficientOrder.OrderCount * contextMap.DcContextCount * qft.Count); + + contextMap.ContextMap = ctxMap; + + if (!JxlDecoderCore.DecodeContextMap(configuration, ref ctxMap, contextMap.ContextCount, reader)) + { + return false; + } + + if (contextMap.ContextCount > 16) + { + throw new InvalidOperationException("Too many distinct contexts in block context map"); + } + + return true; + } +} diff --git a/src/ImageSharp/Formats/Jxl/JxlFrameDimensions.cs b/src/ImageSharp/Formats/Jxl/Processing/JxlFrameDimensions.cs similarity index 98% rename from src/ImageSharp/Formats/Jxl/JxlFrameDimensions.cs rename to src/ImageSharp/Formats/Jxl/Processing/JxlFrameDimensions.cs index 8a7416a57..4ec265f52 100644 --- a/src/ImageSharp/Formats/Jxl/JxlFrameDimensions.cs +++ b/src/ImageSharp/Formats/Jxl/Processing/JxlFrameDimensions.cs @@ -3,7 +3,7 @@ using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.Formats.Jxl; +namespace SixLabors.ImageSharp.Formats.Jxl.Processing; internal sealed class JxlFrameDimensions { diff --git a/src/ImageSharp/Formats/Jxl/Splines/JxlControlPoint.cs b/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlControlPoint.cs similarity index 86% rename from src/ImageSharp/Formats/Jxl/Splines/JxlControlPoint.cs rename to src/ImageSharp/Formats/Jxl/Processing/Splines/JxlControlPoint.cs index 74f1a0c3a..48d94b345 100644 --- a/src/ImageSharp/Formats/Jxl/Splines/JxlControlPoint.cs +++ b/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlControlPoint.cs @@ -3,7 +3,7 @@ using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.Formats.Jxl.Splines; +namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Splines; /// /// A simple pair of first and second 32-bit signed integers diff --git a/src/ImageSharp/Formats/Jxl/Splines/JxlQuantizedSpline.cs b/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlQuantizedSpline.cs similarity index 99% rename from src/ImageSharp/Formats/Jxl/Splines/JxlQuantizedSpline.cs rename to src/ImageSharp/Formats/Jxl/Processing/Splines/JxlQuantizedSpline.cs index 42aed25f8..0e0135c17 100644 --- a/src/ImageSharp/Formats/Jxl/Splines/JxlQuantizedSpline.cs +++ b/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlQuantizedSpline.cs @@ -5,7 +5,7 @@ using System.Buffers; using System.Diagnostics; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.Formats.Jxl.Splines; +namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Splines; internal sealed class JxlQuantizedSpline : IDisposable { diff --git a/src/ImageSharp/Formats/Jxl/Splines/JxlSpline.cs b/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlSpline.cs similarity index 93% rename from src/ImageSharp/Formats/Jxl/Splines/JxlSpline.cs rename to src/ImageSharp/Formats/Jxl/Processing/Splines/JxlSpline.cs index ef65c1d95..f95886b26 100644 --- a/src/ImageSharp/Formats/Jxl/Splines/JxlSpline.cs +++ b/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlSpline.cs @@ -3,7 +3,7 @@ using System.Buffers; -namespace SixLabors.ImageSharp.Formats.Jxl.Splines; +namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Splines; internal sealed class JxlSpline : IDisposable { diff --git a/src/ImageSharp/Formats/Jxl/Splines/JxlSplineDataView.cs b/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlSplineDataView.cs similarity index 82% rename from src/ImageSharp/Formats/Jxl/Splines/JxlSplineDataView.cs rename to src/ImageSharp/Formats/Jxl/Processing/Splines/JxlSplineDataView.cs index 1884b85c6..7b3822d78 100644 --- a/src/ImageSharp/Formats/Jxl/Splines/JxlSplineDataView.cs +++ b/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlSplineDataView.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -namespace SixLabors.ImageSharp.Formats.Jxl.Splines; +namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Splines; internal sealed class JxlSplineDataView { diff --git a/src/ImageSharp/Formats/Jxl/Splines/JxlSplineEntropyContext.cs b/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlSplineEntropyContext.cs similarity index 80% rename from src/ImageSharp/Formats/Jxl/Splines/JxlSplineEntropyContext.cs rename to src/ImageSharp/Formats/Jxl/Processing/Splines/JxlSplineEntropyContext.cs index adb619f5f..b6be2fe51 100644 --- a/src/ImageSharp/Formats/Jxl/Splines/JxlSplineEntropyContext.cs +++ b/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlSplineEntropyContext.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -namespace SixLabors.ImageSharp.Formats.Jxl.Splines; +namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Splines; internal enum JxlSplineEntropyContext : byte { diff --git a/src/ImageSharp/Formats/Jxl/Splines/JxlSplineSegment.cs b/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlSplineSegment.cs similarity index 85% rename from src/ImageSharp/Formats/Jxl/Splines/JxlSplineSegment.cs rename to src/ImageSharp/Formats/Jxl/Processing/Splines/JxlSplineSegment.cs index 7e8bef1be..65f217792 100644 --- a/src/ImageSharp/Formats/Jxl/Splines/JxlSplineSegment.cs +++ b/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlSplineSegment.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -namespace SixLabors.ImageSharp.Formats.Jxl.Splines; +namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Splines; internal struct JxlSplineSegment { diff --git a/src/ImageSharp/Formats/Jxl/Splines/JxlSplineSegmentSpan.cs b/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlSplineSegmentSpan.cs similarity index 81% rename from src/ImageSharp/Formats/Jxl/Splines/JxlSplineSegmentSpan.cs rename to src/ImageSharp/Formats/Jxl/Processing/Splines/JxlSplineSegmentSpan.cs index b4bd52af4..2c65b1695 100644 --- a/src/ImageSharp/Formats/Jxl/Splines/JxlSplineSegmentSpan.cs +++ b/src/ImageSharp/Formats/Jxl/Processing/Splines/JxlSplineSegmentSpan.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -namespace SixLabors.ImageSharp.Formats.Jxl.Splines; +namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Splines; internal struct JxlSplineSegmentSpan(int startInclusive, int endInclusive) {