From 1a23a1a28224d1537d0b7b46a9a76b3f521b0955 Mon Sep 17 00:00:00 2001 From: winscripter <142818255+winscripter@users.noreply.github.com> Date: Thu, 10 Sep 2026 06:05:04 +0400 Subject: [PATCH] Add TOC encoder --- .../Encoder/JxlCoefficientOrderEncoder.cs | 2 +- .../Jxl/Processing/Encoder/JxlTocEncoder.cs | 55 +++++++++++++++++++ .../Formats/Jxl/Processing/JxlToc.cs | 16 ++++-- 3 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 src/ImageSharp/Formats/Jxl/Processing/Encoder/JxlTocEncoder.cs diff --git a/src/ImageSharp/Formats/Jxl/Processing/Encoder/JxlCoefficientOrderEncoder.cs b/src/ImageSharp/Formats/Jxl/Processing/Encoder/JxlCoefficientOrderEncoder.cs index 98171f340a..650717ee7d 100644 --- a/src/ImageSharp/Formats/Jxl/Processing/Encoder/JxlCoefficientOrderEncoder.cs +++ b/src/ImageSharp/Formats/Jxl/Processing/Encoder/JxlCoefficientOrderEncoder.cs @@ -313,7 +313,7 @@ internal static class JxlCoefficientOrderEncoder return true; } - private static bool EncodePermutation(ReadOnlySpan order, int skip, int size, JxlBitWriter writer) + public static bool EncodePermutation(ReadOnlySpan order, int skip, int size, JxlBitWriter writer) { List[] tokens = [[]]; diff --git a/src/ImageSharp/Formats/Jxl/Processing/Encoder/JxlTocEncoder.cs b/src/ImageSharp/Formats/Jxl/Processing/Encoder/JxlTocEncoder.cs new file mode 100644 index 0000000000..c0c38df9fb --- /dev/null +++ b/src/ImageSharp/Formats/Jxl/Processing/Encoder/JxlTocEncoder.cs @@ -0,0 +1,55 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Formats.Jxl.Fields; + +namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Encoder; + +internal static class JxlTocEncoder +{ + public static void WriteTocPermutation(Memory permutation, JxlBitWriter writer) + { + int nPermutation = permutation.Length; + + _ = writer.WithMaxBits((ulong)JxlToc.MaxBits(0), () => + { + if (nPermutation > 0) + { + writer.Write(1, 1); // permutation present + if (!JxlCoefficientOrderEncoder.EncodePermutation( + MemoryMarshal.Cast(permutation.Span), + 0, + permutation.Length, + writer)) + { + return false; + } + } + else + { + writer.Write(1, 0); // no permutation + } + + writer.ZeroPadToByte(); + return true; + }); + } + + public static void WriteTocSizes(Memory groupSizes, JxlBitWriter writer) => + _ = writer.WithMaxBits((ulong)JxlToc.MaxBits(groupSizes.Length), () => + { + Span groupSizesSpan = groupSizes.Span; + + for (int i = 0; i < groupSizesSpan.Length; i++) + { + if (!JxlU32Coder.Write(in JxlToc.TocDistribution, unchecked((uint)groupSizesSpan[i]), writer)) + { + return false; + } + } + + writer.ZeroPadToByte(); + return true; + }); +} diff --git a/src/ImageSharp/Formats/Jxl/Processing/JxlToc.cs b/src/ImageSharp/Formats/Jxl/Processing/JxlToc.cs index b6dfd4e39f..d3de060b83 100644 --- a/src/ImageSharp/Formats/Jxl/Processing/JxlToc.cs +++ b/src/ImageSharp/Formats/Jxl/Processing/JxlToc.cs @@ -11,12 +11,22 @@ namespace SixLabors.ImageSharp.Formats.Jxl.Processing; /// internal static class JxlToc { - private static readonly JxlU32Enc TocDistribution = new( + private const int BitsPerByte = 8; + + private const int MaxTocEntries = 65536; + + public static readonly JxlU32Enc TocDistribution = new( JxlFieldExpressions.Bits(10), JxlFieldExpressions.BitsOffset(14, 2024), JxlFieldExpressions.BitsOffset(22, 17408), JxlFieldExpressions.BitsOffset(30, 4211712)); + public static int MaxBits(int numSizes) + { + int entryBits = JxlU32Coder.MaxEncodedBits(TocDistribution) * numSizes; + return 1 + JxlMath.BitsPerByte + entryBits + JxlMath.BitsPerByte; + } + public static int AcGroupIndex(int pass, int group, int numGroups, int numDcGroups) => 2 + numDcGroups + (pass * numGroups) + group; @@ -30,10 +40,6 @@ internal static class JxlToc return AcGroupIndex(0, 0, numGroups, numDcGroups) + (numGroups * numPasses); } - private const int BitsPerByte = 8; - - private const int MaxTocEntries = 65536; - public static bool ReadToc( Configuration configuration, int tocEntries,