Skip to content

Support for JPEG XL (JXL) images#3153

Draft
winscripter wants to merge 43 commits into
SixLabors:mainfrom
winscripter:jxl-support
Draft

Support for JPEG XL (JXL) images#3153
winscripter wants to merge 43 commits into
SixLabors:mainfrom
winscripter:jxl-support

Conversation

@winscripter

Copy link
Copy Markdown

Prerequisites

  • I have written a descriptive pull-request title
  • I have verified that there are no overlapping pull-requests open
  • I have verified that I am following the existing coding patterns and practice as demonstrated in the repository. These follow strict Stylecop rules 👮.
  • I have provided test coverage for my change (where applicable)

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.

@CLAassistant

CLAassistant commented Jul 15, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

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
@winscripter

Copy link
Copy Markdown
Author

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.

Comment thread src/ImageSharp/Formats/Jxl/Metadata/JxlExifOrientation.cs Outdated
Comment thread src/ImageSharp/Formats/Jxl/Metadata/JxlExtraChannel.cs Outdated
Comment thread src/ImageSharp/Formats/Jxl/Splines/JxlSplineEntropyContext.cs Outdated
Comment thread src/ImageSharp/Formats/Jxl/JxlFrameDimensions.cs Outdated
It is too large for a struct.
Add JxlAnsEntry and JxlAnsSymbol.

See ans_common.h. These correspond to the Entry and Symbol structures within AliasTable.
Comment thread src/ImageSharp/Formats/Jxl/IO/JxlAnsHelper.cs Outdated
Comment thread src/ImageSharp/Formats/Jxl/IO/JxlAnsHelper.cs Outdated
Comment thread src/ImageSharp/Formats/Jxl/JxlThrowHelper.cs Outdated
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.
nonZeroesLeft = (nonZeroesLeft + coveredBlocks - 1) >> log2CoveredBlocks;
k >>= log2CoveredBlocks;

Debug.Assert(k > 0);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to note. We don't use Debug.Assert in this codebase. We have explicit DebugGuard APIs instead

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some cases DebugGuard feels too limiting.

For example, in the following condition:

JXL_DASSERT(!extension_states_.IsBegun() || extension_states_.IsEnded());

I'd have to write:

DebugGuard.IsTrue(!this.extensionStates.IsBegun || this.extensionStates.IsEnded);

where it expects a parameter name, which doesn't fit because 1. it's not a parameter (but a property) and 2. there are multiple properties involved in the assertion.

Any ideas?

@winscripter winscripter Jul 18, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I didn't get it right - the second parameter is a message, not the parameter name.

Would DebugGuard.IsTrue(false, "message") be considered a good replacement for Debug.Fail?

@JimBobSquarePants

Copy link
Copy Markdown
Member

Thanks @winscripter I really appreciate you attempting this.

Examples include but are not limited to stack allocation, array pooling, and SIMD.

On a performance note. I think it would be best if you use these immediately as that can affect design. Any new code should also reuse utility components already available in the library where possible.

In addition, I normally document internal type as well as public types. This stuff is tough and every little helps.

@winscripter

winscripter commented Jul 17, 2026

Copy link
Copy Markdown
Author

@JimBobSquarePants The examples I mentioned were the aggressive performance optimizations that I'd apply when the implementation can encode and decode images properly. I'd prefer not to apply them just yet, because in that case, the optimizations may introduce bugs that would later be difficult to diagnose while the implementation isn't fully complete.

I do consider applying light optimizations right now, e.g. using spans, pooling arrays with Configuration.MemoryAllocator.Allocate, inlining attributes, moving checks to debug assertions, etc. These optimizations don't largely differ from the reference implementation, so if things go wrong, I can compare my implementation with the reference implementation and spot the issue easily.

I'd consider documenting the internal stuff, but it might be easier said than done, because not all things in libjxl source are documented.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants