Support for JPEG XL (JXL) images - #3153
Conversation
Implementation of ac_strategy.h and ac_strategy.c
For now JxlMemoryManager will be a wrapper around MemoryPool<T>.
Implementation of image.h and image.c; AC strategy implementation was slightly adjusted to reduce errors.
This is an implementation of field_encodings.h. Note that I avoided implementing EnumValid() and Values() functions, as we have dedicated methods in .NET to do exactly that (Enum.IsDefined, Enum.GetValues)
Implementation of spline.h
Implemented ANS constants
|
While I'm working on this, I'd like to note something important. Libjxl is licensed under the BSD 3-Clause license, and since I'm using libjxl code as reference, that means the license must be included. I'm not really sure what would be the proper way to include the license. I might place the LICENSE.txt file in the Jxl folder or add a README linking to the libjxl repo. |
See ans_common.h
It is too large for a struct.
See ans_common.h
Add JxlAnsEntry and JxlAnsSymbol. See ans_common.h. These correspond to the Entry and Symbol structures within AliasTable.
Currently, there's a VarLenUint8/VarLenUint16 as well as histogram parsing implementation. I will additionally have to implement parsing of ANS codes, uint config and LZ77 parameters.
See convolve.h
See dct_scales.h and dct_scales.cc
See pack_signed.h
See loop_filter.h, loop_filter.cc, epf.h and epf.cc
See fields.h and fields.cc
See frame_header.h
See butteraugli.h Added the parameters structure
…dering * CMS - Color Management System
| // Prefer arrays so we can set values like this: | ||
| // JxlOpsinInverseMatrix m = ...; | ||
| // m.OpsinBiases[0] = 1f; | ||
| // An InlineArray can't do that. | ||
| public float[] OpsinBiases { get; set; } = new float[3]; | ||
|
|
||
| public float[] QuantBiases { get; set; } = new float[4]; |
There was a problem hiding this comment.
An InlineArray can't do that.
It's good that you followed the suggestion about properties, but in this case that's the reason why "InlineArray can't do that".
When they're just a field, then it's possible, so:
| // Prefer arrays so we can set values like this: | |
| // JxlOpsinInverseMatrix m = ...; | |
| // m.OpsinBiases[0] = 1f; | |
| // An InlineArray can't do that. | |
| public float[] OpsinBiases { get; set; } = new float[3]; | |
| public float[] QuantBiases { get; set; } = new float[4]; | |
| public InlineArray3<float> OpsinBiases; | |
| public InlineArray4<float> QuantBiases; |
and it avoids the allocation of the two float arrays.
| /// <returns>Boolean indicating whether the coordinates are out of bounds</returns> | ||
| private static bool IsOutOfBounds(int a, int b, int size) | ||
| { | ||
| int position = a + b; |
There was a problem hiding this comment.
Is there a possiblity for overflow (at least theoretically)?
If so, could use long position = a + b to be safe.
| // Use arrays instead of InlineArrays because, with inline arrays we can't do: | ||
| // JxlOpsinParameters parameters = ...; | ||
| // parameters.OpsinBiasesCbrt[0] /* <-- error */ = 1.25f; |
There was a problem hiding this comment.
Same as above. Use fields, not properties here.
The InverseOpsinMatrix with 36 elements is 144 bytes, so still OK when on stack space.
|
|
||
| public static bool ReadPermutation(int skip, int size, Span<int> order, JxlBitReader bitReader, JxlAnsSymbolReader reader, Span<byte> contextMap) | ||
| { | ||
| Span<uint> lehmer = stackalloc uint[size]; |
There was a problem hiding this comment.
Is size limited to some maximum value?
If so, there should be an assert here to make it clear.
For the stackalloc it's better to use a constant value, then slice it if needed. Thus produces most of the time better code. E.g. stackalloc uint[128].Slice(0, size).
| public static bool ReadPermutation(int skip, int size, Span<int> order, JxlBitReader bitReader, JxlAnsSymbolReader reader, Span<byte> contextMap) | ||
| { | ||
| Span<uint> lehmer = stackalloc uint[size]; | ||
| lehmer.Clear(); |
There was a problem hiding this comment.
👍🏻 for being safe here, as there's no guarantee for zeroing by the runtime (it should do so, but there're edge case where it isn't).
And if once [SkipLocalsInit] is applied in this project (or is it already?), then this prevent a hard to find 🐛.
Prerequisites
Description
This is a work-in-progress PR whose goal is to introduce decoding and encoding of JPEG XL (*.jxl) images.
Reference software
I use libjxl as reference. See https://github.com/libjxl/libjxl.
Performance
I will begin by applying light optimizations as I implement parts of the JPEG XL codec. Once the codec seems complete enough to handle decoding and encoding of JPEG XL images, I will apply heavier optimizations. Examples include but are not limited to stack allocation, array pooling, and SIMD.
Other components
The JPEG XL codec, additionally, uses the LZ77 and Brotli compression codec. I will also have to implement those eventually.
Implementations
The JPEG XL codec lives under
src/ImageSharp/Formats/Jxl.Brotli and LZ77 implementations will live under
src/ImageSharp/Compression.Testing
I will start adding tests whenever the codec is complete enough to handle decoding of JPEG XL images.
Additionally, JPEG XL reference software, libjxl, contains its own tests too, which I might also implement without modification.