Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
116 commits
Select commit Hold shift + click to select a range
85c851b
Add JPEG XL format
winscripter Jul 14, 2026
996e93d
Implement ac_context.h
winscripter Jul 14, 2026
d87178f
Implemented frame_dimensions.h plus part of ac_strategy.h
winscripter Jul 14, 2026
1ac6140
Implement AC strategy
winscripter Jul 15, 2026
31b5505
Implement JxlMemoryManager
winscripter Jul 15, 2026
21ff33f
Implement image and memory buffers
winscripter Jul 15, 2026
6fea920
Add metadata models
winscripter Jul 15, 2026
762edd1
Add headers & aspect ratio helpers
winscripter Jul 15, 2026
487410e
Implement field encodings, move IJxlFields
winscripter Jul 15, 2026
ac1c866
Add xorshift implemetation
winscripter Jul 15, 2026
8581222
It's Jxl not Jpeg
winscripter Jul 15, 2026
9b58f4b
Implement spline abstractions
winscripter Jul 15, 2026
064376a
Add quantized spline implementations
winscripter Jul 16, 2026
90680b7
Prefer the term "coefficient"
winscripter Jul 16, 2026
1e40482
Start work on ANS entropy
winscripter Jul 16, 2026
396cd8d
Implement JxlAnsHelper.GetPopulationCountPrecision
winscripter Jul 16, 2026
cb364fa
Turn JxlFrameDimensions into a sealed class
winscripter Jul 16, 2026
528149f
Implement CreateFlatHistogram
winscripter Jul 16, 2026
490f02f
Add ANS entropy structs
winscripter Jul 16, 2026
73941c1
Prefer byte for enums
winscripter Jul 16, 2026
20c2dd3
Implement ANS entropy helpers
winscripter Jul 16, 2026
fed0af3
Add bit-stream reader
winscripter Jul 16, 2026
25e41da
Avoid 'using static'
winscripter Jul 16, 2026
4ec9b95
Simplify
winscripter Jul 16, 2026
b716d4e
Add ANS VarLen & histogram parser
winscripter Jul 16, 2026
1381def
Fix memory leaks
winscripter Jul 16, 2026
8ffb41a
Don't use end of stream singleton
winscripter Jul 16, 2026
3ed56c9
Add ANS hybrid uint configuration & LZ77 parameters model
winscripter Jul 16, 2026
7f35b1a
Implement Lehmer codes
winscripter Jul 16, 2026
57eadbb
Implement noise shared logic
winscripter Jul 16, 2026
6de4a89
Add alpha blending
winscripter Jul 16, 2026
289fecd
Move AC strategy & Coefficients stuff into Processing
winscripter Jul 17, 2026
b15c190
Add symmetric weights; fix broken using
winscripter Jul 17, 2026
b3023f2
Add separable weights
winscripter Jul 17, 2026
73c7cec
Add DCT scales
winscripter Jul 17, 2026
7223d98
Add DCT memory, make JxlImage3<T> implement IDisposable
winscripter Jul 17, 2026
51b7765
Implement signed packing
winscripter Jul 17, 2026
446e4a5
Add loop filter
winscripter Jul 18, 2026
decc0b2
Fully implement JPEG XL fields
winscripter Jul 18, 2026
a6a0263
Implement visitor for JxlBitDepth
winscripter Jul 18, 2026
6aa313f
Add matrices
winscripter Jul 18, 2026
d401b71
Fix errors
winscripter Jul 18, 2026
a803f01
Add Y'Cb'Cr chroma subsampling as part of the frame header
winscripter Jul 18, 2026
16c55f3
Add frame header
winscripter Jul 19, 2026
ded8906
Move Metadata folder to IO
winscripter Jul 19, 2026
674f82a
Add quantizer
winscripter Jul 20, 2026
07f6be0
Fix memory leak
winscripter Jul 20, 2026
b720196
Add opsin inverse parameters, some quantizer weight work
winscripter Jul 20, 2026
2758454
Move, add entropy coding common functions
winscripter Jul 21, 2026
6eda7e2
Remove aggressive inlining attributes, fix usings
winscripter Jul 21, 2026
f71bab2
Use distinct read-only spans
winscripter Jul 21, 2026
abafaf8
Add CFL
winscripter Jul 21, 2026
9c6b4ef
Add Huffman common methods
winscripter Jul 22, 2026
3591250
Start work on Butteraugli
winscripter Jul 22, 2026
765c892
Implement Butteraugli core functions
winscripter Jul 24, 2026
0d159b9
Add CMS* prototype, XYB decoding, TOC, convolution and coefficient or…
winscripter Aug 1, 2026
083385b
Use inline arrays in quantizer
winscripter Aug 1, 2026
a1cae71
Prefer const
winscripter Aug 1, 2026
eb80187
Don't use System.Diagnostics.Debug
winscripter Aug 1, 2026
79e8ce7
Add Move to Front transform
winscripter Aug 6, 2026
d1f6646
Prefer inline arrays
winscripter Aug 6, 2026
fe41799
Prevent potential overflow
winscripter Aug 6, 2026
8209aa1
Refactor
winscripter Aug 6, 2026
074ff1b
Validate the size parameter in JxlCoefficientOrder.ReadPermutation
winscripter Aug 6, 2026
f19c879
Add more implementations and prototypes
winscripter Aug 8, 2026
ff98ffd
Add image copy operations
winscripter Aug 8, 2026
e718a4a
Implement image operations
winscripter Aug 8, 2026
048945c
Reduce number of errors
winscripter Aug 8, 2026
4f71c52
Implement JPEG XL numerics functions & reduce errors
winscripter Aug 8, 2026
4d0a468
Add rectangle support to images
winscripter Aug 8, 2026
2c517a2
Document JxlPlane<T> and JxlPlaneBase
winscripter Aug 8, 2026
50813c1
Add passes decoder state prototype & reduce errors in JxlQuantizedSpline
winscripter Aug 8, 2026
27a848c
Add DCT, transpose, and performance improvements
winscripter Aug 12, 2026
0d9aea4
Remove GC.SuppressFinalize(this)
winscripter Aug 12, 2026
20e3a34
Add image bundle
winscripter Aug 12, 2026
6e432ca
Use inline arrays in Butteraugli
winscripter Aug 12, 2026
4308af8
Merge branch 'SixLabors:main' into jxl-support
winscripter Aug 13, 2026
8b4ff41
First prototype of JxlDecoderCore
winscripter Aug 15, 2026
e03a581
Add JPEG XL container prototype & file type box
winscripter Aug 17, 2026
2d12bc6
Zero-copy input access (prototype 1)
winscripter Aug 18, 2026
08c13fc
Performance improvements
winscripter Aug 18, 2026
6ba0d37
Zero-copy input access (prototype 2)
winscripter Aug 18, 2026
c535893
Zero-copy input access (prototype 3)
winscripter Aug 18, 2026
75f676d
Add prototype of modular
winscripter Aug 24, 2026
e449656
Merge branch 'SixLabors:main' into jxl-support
winscripter Aug 24, 2026
dfd99a0
Reduce errors in AC strategy code
winscripter Aug 24, 2026
a2f8fe6
Reduce errors
winscripter Aug 24, 2026
352b14d
Reduce errors, remove unused constant
winscripter Aug 24, 2026
093d846
Finish inverse RCT
winscripter Aug 24, 2026
c5a7bb8
Complete RCT
winscripter Aug 24, 2026
c8b0a5d
Simplify decoder core & add palette shared methods
winscripter Aug 24, 2026
c079cf9
Add missing types, rename JxlBitDepth metadata to JxlBitDepthMetadata…
winscripter Aug 24, 2026
7e23670
Add CodestreamMarker, don't manually check for out-of-bounds
winscripter Aug 24, 2026
b8f4094
Reduce errors
winscripter Aug 24, 2026
2b43fd6
Simplify
winscripter Aug 24, 2026
9f8eb4a
Add box content decoder with Brotli compression & reduce errors
winscripter Aug 25, 2026
315ea0f
Reduce errors & refine documentation
winscripter Aug 25, 2026
57958f3
Reduce errors & remove unnecessary if statements
winscripter Aug 25, 2026
0678f35
Add missing types, reduce errors
winscripter Aug 25, 2026
4118c4a
Quantizer improvements, reduce errors
winscripter Aug 25, 2026
874ec5b
Complete quantizer encoding
winscripter Aug 25, 2026
acc474e
Complete modular transforms, context prediction
winscripter Aug 31, 2026
7b8749d
Don't use stackalloc for two bytes
winscripter Aug 31, 2026
15c32fe
Prefer Math.DivRem
winscripter Aug 31, 2026
de8c644
Use Math.DivRem
winscripter Aug 31, 2026
a5d5ab6
Prefer byte
winscripter Aug 31, 2026
1b6e824
Don't use GetWReference (it should return span)
winscripter Aug 31, 2026
c6c6942
Parenthesize
winscripter Aug 31, 2026
79b0113
Don't use stackalloc
winscripter Aug 31, 2026
e7d3608
Remove SuppressFinalize from sealed class
winscripter Aug 31, 2026
e6ed4ba
Use Math.Clamp
winscripter Aug 31, 2026
4858ef3
Use StartsWith
winscripter Aug 31, 2026
2835528
Remove try/finally
winscripter Aug 31, 2026
90ddb9d
Add JPEG parsed data
winscripter Aug 31, 2026
3059910
Use InlineArray for color correlation
winscripter Aug 31, 2026
a955946
Add JPEG data constants
winscripter Aug 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/ImageSharp/Common/Helpers/Numerics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1033,4 +1033,13 @@ public static nuint Vector512Count<TVector>(this ReadOnlySpan<float> span)
public static nuint Vector512Count<TVector>(int length)
where TVector : struct
=> (uint)length / (uint)Vector512<TVector>.Count;

/// <summary>
/// Computes the average of two integers.
/// </summary>
/// <param name="x">First integer</param>
/// <param name="y">Second integer</param>
/// <returns>The average of x, y.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Average(int x, int y) => (x + y + ((x > y) ? 1 : 0)) >> 1;
}
40 changes: 40 additions & 0 deletions src/ImageSharp/Common/Helpers/Vector128Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -859,4 +859,44 @@ public static Vector128<sbyte> UnpackLow(Vector128<sbyte> left, Vector128<sbyte>
Vector128<sbyte> unpacked = Vector128.Create(left.GetLower(), right.GetLower());
return Vector128.ShuffleNative(unpacked, Vector128.Create(0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15));
}

/// <summary>
/// Interleaves the lower half of the vector.
/// </summary>
/// <param name="a">First vector</param>
/// <param name="b">Second vector</param>
/// <returns>
/// <c>{ a[0], b[0], a[1], b[1] }</c>
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector128<int> InterleaveLower(Vector128<int> a, Vector128<int> b)
{
Vector128<int> shuffledA = Vector128.Shuffle(a, Vector128.Create(0, 0, 1, 1));
Vector128<int> shuffledB = Vector128.Shuffle(b, Vector128.Create(0, 0, 1, 1));

Vector128<int> maskA = Vector128.Create(-1, 0, -1, 0);
Vector128<int> maskB = Vector128.Create(0, -1, 0, -1);

return (shuffledA & maskA) | (shuffledB & maskB);
}

/// <summary>
/// Interleaves the upper half of the vector.
/// </summary>
/// <param name="a">First vector</param>
/// <param name="b">Second vector</param>
/// <returns>
/// <c>{ a[2], b[2], a[3], b[3] }</c>
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector128<int> InterleaveUpper(Vector128<int> a, Vector128<int> b)
{
Vector128<int> shuffledA = Vector128.Shuffle(a, Vector128.Create(2, 2, 3, 3));
Vector128<int> shuffledB = Vector128.Shuffle(b, Vector128.Create(2, 2, 3, 3));

Vector128<int> maskA = Vector128.Create(-1, 0, -1, 0);
Vector128<int> maskB = Vector128.Create(0, -1, 0, -1);

return (shuffledA & maskA) | (shuffledB & maskB);
}
}
166 changes: 166 additions & 0 deletions src/ImageSharp/Common/Helpers/Vector256Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -397,4 +397,170 @@ public static Vector256<byte> UnpackLow(Vector256<byte> left, Vector256<byte> ri

return Vector256.Create(lo, hi);
}

/// <summary>
/// Multiplies only the even indices of the two 256-bit vectors,
/// producing half as many elements of twice the element width.
/// </summary>
/// <param name="left">Left vector to multiply.</param>
/// <param name="right">Right vector to multiply</param>
/// <returns>
/// <code>
/// {
/// A[0] * B[0],
/// A[2] * B[2],
/// A[4] * B[4],
/// A[6] * B[6]
/// }
/// </code>
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<long> MultiplyEven(Vector256<int> left, Vector256<int> right)
=> Vector256.Create(
left[0] * right[0],
left[2] * right[2],
left[4] * right[4],
left[6] * right[6]);

/// <summary>
/// Multiplies only the odd indices of the two 256-bit vectors,
/// producing half as many elements of twice the element width.
/// </summary>
/// <param name="left">Left vector to multiply.</param>
/// <param name="right">Right vector to multiply</param>
/// <returns>
/// <code>
/// {
/// A[1] * B[1],
/// A[3] * B[3],
/// A[5] * B[5],
/// A[7] * B[7]
/// }
/// </code>
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<long> MultiplyOdd(Vector256<int> left, Vector256<int> right)
=> Vector256.Create(
left[1] * right[1],
left[3] * right[3],
left[5] * right[5],
left[7] * right[7]);

/// <summary>
/// Produces a vector by interleaving the even-indexed elements
/// of the left and right vectors.
/// </summary>
/// <param name="left">Left vector to interleave.</param>
/// <param name="right">Right vector to interleave.</param>
/// <returns>
/// <code>
/// {
/// A[0], B[0],
/// A[2], B[2],
/// A[4], B[4],
/// A[6], B[6]
/// }
/// </code>
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<int> InterleaveEven(
Vector256<int> left,
Vector256<int> right)
=> Vector256.Create(
left[0],
right[0],
left[2],
right[2],
left[4],
right[4],
left[6],
right[6]);

/// <summary>
/// Produces a vector by interleaving the odd-indexed elements
/// of the left and right vectors.
/// </summary>
/// <param name="left">Left vector to interleave.</param>
/// <param name="right">Right vector to interleave.</param>
/// <returns>
/// <code>
/// {
/// A[1], B[1],
/// A[3], B[3],
/// A[5], B[5],
/// A[7], B[7]
/// }
/// </code>
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<int> InterleaveOdd(
Vector256<int> left,
Vector256<int> right)
=> Vector256.Create(
left[1],
right[1],
left[3],
right[3],
left[5],
right[5],
left[7],
right[7]);

/// <summary>
/// Produces a vector with masks where 0xFFFFFFFF specifies
/// that the left value does not equal to the right value and
/// 0x00000000 specifies that the value equals to the
/// right value.
/// </summary>
/// <param name="left">Left vector to compare for inequality.</param>
/// <param name="right">Right vector to compare for inequality.</param>
/// <returns>
/// 0xFFFFFFFF for values that aren't equal, 0x00000000 for
/// values that are equal. This is essentially the inverse of
/// <see cref="Vector256.Equals{T}(Vector256{T}, Vector256{T})"/>.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<int> NotEqual(
Vector256<int> left,
Vector256<int> right) => ~Vector256.Equals(left, right);

/// <summary>
/// Interleaves the lower half of the vector.
/// </summary>
/// <param name="a">First vector</param>
/// <param name="b">Second vector</param>
/// <returns>
/// <c>{ a[0], b[0], a[1], b[1], a[2], b[2], a[3], b[3] }</c>
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<int> InterleaveLower(Vector256<int> a, Vector256<int> b)
{
Vector256<int> shuffledA = Vector256.Shuffle(a, Vector256.Create(0, 0, 1, 1, 2, 2, 3, 3));
Vector256<int> shuffledB = Vector256.Shuffle(b, Vector256.Create(0, 0, 1, 1, 2, 2, 3, 3));

Vector256<int> maskA = Vector256.Create(-1, 0, -1, 0, -1, 0, -1, 0);
Vector256<int> maskB = Vector256.Create(0, -1, 0, -1, 0, -1, 0, -1);

return (shuffledA & maskA) | (shuffledB & maskB);
}

/// <summary>
/// Interleaves the upper half of the vector.
/// </summary>
/// <param name="a">First vector</param>
/// <param name="b">Second vector</param>
/// <returns>
/// <c>{ a[4], b[4], a[5], b[5], a[6], b[6], a[7], b[7] }</c>
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<int> InterleaveUpper(Vector256<int> a, Vector256<int> b)
{
Vector256<int> shuffledA = Vector256.Shuffle(a, Vector256.Create(4, 4, 5, 5, 6, 6, 7, 7));
Vector256<int> shuffledB = Vector256.Shuffle(b, Vector256.Create(4, 4, 5, 5, 6, 6, 7, 7));

Vector256<int> maskA = Vector256.Create(-1, 0, -1, 0, -1, 0, -1, 0);
Vector256<int> maskB = Vector256.Create(0, -1, 0, -1, 0, -1, 0, -1);

return (shuffledA & maskA) | (shuffledB & maskB);
}
}
22 changes: 21 additions & 1 deletion src/ImageSharp/Common/InlineArray.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

// <auto-generated />
Expand Down Expand Up @@ -71,6 +71,24 @@ internal struct InlineArray26<T>
private T t;
}

/// <summary>
/// Represents a safe, fixed sized buffer of 32 elements.
/// </summary>
[InlineArray(32)]
internal struct InlineArray32<T>
{
private T t;
}

/// <summary>
/// Represents a safe, fixed sized buffer of 33 elements.
/// </summary>
[InlineArray(33)]
internal struct InlineArray33<T>
{
private T t;
}

/// <summary>
/// Represents a safe, fixed sized buffer of 36 elements.
/// </summary>
Expand All @@ -88,3 +106,5 @@ internal struct InlineArray256<T>
{
private T t;
}


2 changes: 1 addition & 1 deletion src/ImageSharp/Common/InlineArray.tt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp;
<#GenerateInlineArrays();#>

<#+
private static int[] Lengths = [4, 8, 14, 16, 18, 19, 26, 36, 256];
private static int[] Lengths = [4, 8, 14, 16, 18, 19, 26, 32, 33, 36, 256];

void GenerateInlineArrays()
{
Expand Down
27 changes: 27 additions & 0 deletions src/ImageSharp/Formats/Jxl/Cms/JxlCieXyPrimaries.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

using SixLabors.ImageSharp.ColorProfiles;

namespace SixLabors.ImageSharp.Formats.Jxl.Cms;

/// <summary>
/// RGB primaries for CIEXY
/// </summary>
internal struct JxlCieXyPrimaries
{
/// <summary>
/// Gets or sets the R component
/// </summary>
public CieXyChromaticityCoordinates R { get; set; }

/// <summary>
/// Gets or sets the G component
/// </summary>
public CieXyChromaticityCoordinates G { get; set; }

/// <summary>
/// Gets or sets the B component
/// </summary>
public CieXyChromaticityCoordinates B { get; set; }
}
77 changes: 77 additions & 0 deletions src/ImageSharp/Formats/Jxl/Cms/JxlColorEncoding.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

namespace SixLabors.ImageSharp.Formats.Jxl.Cms;

internal sealed class JxlColorEncoding
{
public JxlWhitePoint WhitePoint { get; set; } = JxlWhitePoint.D65;

public JxlPrimaries Primaries { get; set; } = JxlPrimaries.SRgb;

public JxlRenderingIntent RenderingIntent { get; set; } = JxlRenderingIntent.Relative;

public bool HaveFields { get; set; } = true;

public JxlIccBytes? Icc { get; set; }

public JxlColorSpace ColorSpace { get; set; } = JxlColorSpace.Rgb;

public bool Cmyk { get; set; }

public JxlCustomTransferFunction TransferFunction { get; set; }

public JxlCustomXy White { get; set; }

public JxlCustomXy Red { get; set; }

public JxlCustomXy Green { get; set; }

public JxlCustomXy Blue { get; set; }

public bool HasPrimaries => this.ColorSpace is not (JxlColorSpace.Gray or JxlColorSpace.Xyb);

public int Channels => (this.ColorSpace == JxlColorSpace.Gray) ? 1 : 3;

public bool TryGetPrimaries(out JxlCieXyPrimaries xy)
{
xy = default;

if (!this.HasPrimaries || !this.HasPrimaries)
{
return false;
}

switch (this.Primaries)
{
case JxlPrimaries.Custom:
xy.R = this.Red.GetValue();
xy.G = this.Green.GetValue();
xy.B = this.Blue.GetValue();
break;

case JxlPrimaries.SRgb:
xy.R = new(0.639998686f, 0.330010138f);
xy.G = new(0.300003784f, 0.600003357f);
xy.B = new(0.150002046f, 0.059997204f);
break;

case JxlPrimaries.Bt2020:
xy.R = new(0.708f, 0.292f);
xy.G = new(0.170f, 0.797f);
xy.B = new(0.131f, 0.046f);
break;

case JxlPrimaries.P3:
xy.R = new(0.680f, 0.320f);
xy.G = new(0.265f, 0.690f);
xy.B = new(0.150f, 0.060f);
break;

default:
throw new InvalidOperationException("Invalid primaries: " + this.Primaries);
}

return true;
}
}
Loading