Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 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
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
17 changes: 17 additions & 0 deletions src/ImageSharp/Formats/Jxl/Fields/IJxlFields.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

namespace SixLabors.ImageSharp.Formats.Jxl.Fields;

/// <summary>
/// Abstracts enumeration of all fields into a visitor.
/// </summary>
internal interface IJxlFields
{
/// <summary>
/// Visits all fields into the specified JXL visitor.
/// </summary>
/// <param name="visitor">The visitor to use to visit all fields.</param>
/// <returns>Status of the visit operation.</returns>
public bool Visit(JxlVisitor visitor);
}
35 changes: 35 additions & 0 deletions src/ImageSharp/Formats/Jxl/Fields/JxlAllDefaultVisitor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

namespace SixLabors.ImageSharp.Formats.Jxl.Fields;

internal sealed class JxlAllDefaultVisitor : JxlVisitorBase
{
public bool IsAllDefault { get; private set; } = true;

public override bool Bits(int bits, uint defaultValue, ref uint value)
{
this.IsAllDefault = value == defaultValue;
return true;
}

public override bool U32(JxlU32Enc enc, uint defaultValue, ref uint value)
{
this.IsAllDefault = value == defaultValue;
return true;
}

public override bool U64(ulong defaultValue, ref ulong value)
{
this.IsAllDefault = value == defaultValue;
return true;
}

public override bool F16(float defaultValue, ref float value)
{
this.IsAllDefault = MathF.Abs(value - defaultValue) < 1E-6f;
return true;
}

public override bool AllDefault(IJxlFields fields, ref bool allDefault) => false;
}
41 changes: 41 additions & 0 deletions src/ImageSharp/Formats/Jxl/Fields/JxlBitsCoder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Formats.Jxl.IO;

namespace SixLabors.ImageSharp.Formats.Jxl.Fields;

/// <summary>
/// Raw bits coder
/// </summary>
internal static class JxlBitsCoder
{
/// <summary>
/// Maximum number of encodeable bits. Since this coder encodes
/// bits raw, this happens to be whatever is passed to it.
/// </summary>
// Looks like that's what the function does (fields.cc:406):
// it returns whatever is passed to it.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int MaxEncodedBits(int bits) => bits;

public static bool CanEncode(int bits, uint value, ref int encodedBits)
{
encodedBits = bits;
if (value >= (1 << bits))
{
DebugGuard.IsTrue(false, "Value is too large");

return false;
}

return true;
}

// NOTE: BitsCoder::Read (fields.cc:418) returns a uint32_t,
// suggesting the input bit size does not exceed 32 bits.
public static uint Read(uint bits, JxlBitReader reader) => reader.ReadBits32(bits);

public static uint Read(int bits, JxlBitReader reader) => reader.ReadBits32((uint)bits);
}
89 changes: 89 additions & 0 deletions src/ImageSharp/Formats/Jxl/Fields/JxlBundle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

using SixLabors.ImageSharp.Formats.Jxl.IO;

namespace SixLabors.ImageSharp.Formats.Jxl.Fields;

/// <summary>
/// An <see cref="IJxlFields"/> helper.
/// </summary>
internal static class JxlBundle
{
/// <summary>
/// Initializes the specified JXL fields.
/// </summary>
/// <param name="fields">The JXL fields.</param>
public static void Init(IJxlFields fields)
{
JxlInitVisitor initVisitor = new();

if (!initVisitor.Visit(fields))
{
DebugGuard.IsTrue(false, "Init should never fail");
}
}

/// <summary>
/// Sets all JXL fields provided by the input value to their defaults.
/// </summary>
/// <param name="fields">The JXL fields.</param>
public static void SetDefault(IJxlFields fields)
{
JxlSetDefaultVisitor visitor = new();

if (!visitor.Visit(fields))
{
DebugGuard.IsTrue(false, "SetDefault should never fail");
}
}

/// <summary>
/// Returns a value indicating whether every value provided by this
/// field is a default value. If at least one field isn't a default
/// value, the method returns false.
/// </summary>
/// <param name="fields">The JXL fields.</param>
/// <returns>A boolean indicating whether or not are all values initialized to their default values.</returns>
public static bool AllDefault(IJxlFields fields)
{
JxlAllDefaultVisitor allDefaultVisitor = new();

if (!allDefaultVisitor.Visit(fields))
{
DebugGuard.IsTrue(false, "AllDefault should never fail");
}

return allDefaultVisitor.IsAllDefault;
}

/// <summary>
/// Reads the fields from a bit-reader.
/// </summary>
/// <param name="reader">The bit-reader.</param>
/// <param name="fields">The fields.</param>
/// <returns>Status of the read operation.</returns>
public static bool Read(JxlBitReader reader, IJxlFields fields)
{
JxlReadVisitor visitor = new(reader);
if (!visitor.Visit(fields))
{
return false;
}

return visitor.OK;
}

/// <summary>
/// Tries to read the fields from a bit-reader.
/// </summary>
/// <param name="reader">The bit-reader.</param>
/// <param name="fields">The fields.</param>
/// <returns>Status of the read operation.</returns>
public static bool CanRead(JxlBitReader reader, IJxlFields fields)
{
JxlReadVisitor visitor = new(reader);
_ = visitor.Visit(fields);
return visitor.OK;
}
}
118 changes: 118 additions & 0 deletions src/ImageSharp/Formats/Jxl/Fields/JxlCanEncodeVisitor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

using System.Numerics;

namespace SixLabors.ImageSharp.Formats.Jxl.Fields;

internal sealed class JxlCanEncodeVisitor : JxlVisitorBase
{
private long encodedBits;
private ulong extensions;
private long posAfterExt;

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

public override bool Bits(int bits, uint defaultValue, ref uint value)
{
int enc = 0;
this.OK &= JxlBitsCoder.CanEncode(bits, value, ref enc);
this.encodedBits += enc;
return true;
}

public override bool U32(JxlU32Enc enc, uint defaultValue, ref uint value)
{
int encBits = 0;
this.OK &= JxlU32Coder.CanEncode(enc, value, ref encBits);
this.encodedBits += encBits;
return true;
}

public override bool U64(ulong defaultValue, ref ulong value)
{
int encBits = 0;
this.OK &= JxlU64Coder.CanEncode(value, ref encBits);
this.encodedBits += encBits;
return true;
}

public override bool F16(float defaultValue, ref float value)
{
int encBits = 0;
this.OK &= JxlF16Coder.CanEncode(value, ref encBits);
this.encodedBits += encBits;
return true;
}

public override bool AllDefault(IJxlFields fields, ref bool allDefault)
{
allDefault = JxlBundle.AllDefault(fields);
if (!this.Boolean(true, ref allDefault))
{
return false;
}

return allDefault;
}

public override bool BeginExtensions(ref ulong extensions)
{
if (!base.BeginExtensions(ref extensions))
{
return false;
}

this.extensions = extensions;

if (extensions != 0uL)
{
if (this.posAfterExt != 0)
{
return false;
}

this.posAfterExt = this.encodedBits;

if (this.posAfterExt == 0)
{
return false;
}
}

return true;
}

public bool GetSizes(ref int extensionBits, ref long totalBits)
{
if (!this.OK)
{
return false;
}

extensionBits = 0;
totalBits = this.encodedBits;

if (this.posAfterExt != 0)
{
if (this.encodedBits < this.posAfterExt)
{
return false;
}

extensionBits = (int)this.encodedBits - (int)this.posAfterExt;
int encodedBits = 0;
this.OK &= JxlU64Coder.CanEncode(extensionBits, ref encodedBits);
totalBits += encodedBits;

for (int i = 1; i < BitOperations.PopCount(this.extensions); i++)
{
encodedBits = 0;
this.OK &= JxlU64Coder.CanEncode(0, ref encodedBits);
totalBits += encodedBits;
}
}

return true;
}
}
42 changes: 42 additions & 0 deletions src/ImageSharp/Formats/Jxl/Fields/JxlExtensionStates.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

namespace SixLabors.ImageSharp.Formats.Jxl.Fields;

internal sealed class JxlExtensionStates
{
private ulong begun;
private ulong ended;

public bool IsBegun => (this.begun & 1) != 0;

public bool IsEnded => (this.ended & 1) != 0;

public void Push()
{
this.begun <<= 1;
this.ended <<= 1;
}

public void Pop()
{
this.begun >>= 1;
this.ended >>= 1;
}

public void Begin()
{
DebugGuard.IsFalse(this.IsBegun, nameof(this.IsBegun), "This must be false.");
DebugGuard.IsFalse(this.IsEnded, nameof(this.IsEnded), "This must be false.");

this.begun++;
}

public void End()
{
DebugGuard.IsTrue(this.IsBegun, nameof(this.IsBegun), "This must be true.");
DebugGuard.IsFalse(this.IsEnded, nameof(this.IsEnded), "This must be false.");

this.ended++;
}
}
Loading