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

namespace SixLabors.ImageSharp.Formats.Jxl.Cms;

/// <summary>
/// Supported, JPEG XL-specific color space types.
/// </summary>
internal enum JxlColorSpace : byte
{
/// <summary>
/// Trichromatic color data. This also includes CMYK if Black
/// ExtraChannelInfo is present.
/// </summary>
Rgb,

/// <summary>
/// Single-channel data.
/// </summary>
Gray,

/// <summary>
/// Like Rgb but fixed values for primaries.
/// </summary>
Xyb,

/// <summary>
/// Unknown color space
/// </summary>
Unknown
}
109 changes: 109 additions & 0 deletions src/ImageSharp/Formats/Jxl/Cms/JxlCustomTransferFunction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

namespace SixLabors.ImageSharp.Formats.Jxl.Cms;

internal struct JxlCustomTransferFunction
{
private const uint MaxGamma = 8192;
private const uint GammaMultiplier = 10000000;

public JxlCustomTransferFunction()
{
}

public bool HaveGamma { get; set; }

public uint Gamma { get; set; }

public JxlTransferFunction TransferFunction { get; set; } = JxlTransferFunction.SRgb;

public readonly bool IsUnknown => !this.HaveGamma && this.TransferFunction == JxlTransferFunction.Unknown;

public readonly bool IsSrgb => !this.HaveGamma && this.TransferFunction == JxlTransferFunction.SRgb;

public readonly bool IsLinear => !this.HaveGamma && this.TransferFunction == JxlTransferFunction.Linear;

public readonly bool IsPq => !this.HaveGamma && this.TransferFunction == JxlTransferFunction.Pq;

public readonly bool IsHlg => !this.HaveGamma && this.TransferFunction == JxlTransferFunction.Hlg;

public readonly bool Is709 => !this.HaveGamma && this.TransferFunction == JxlTransferFunction.Bt709;

public readonly bool IsDci => !this.HaveGamma && this.TransferFunction == JxlTransferFunction.Dci;

public readonly JxlTransferFunction GetTransferFunction()
{
if (this.HaveGamma)
{
return JxlTransferFunction.Unknown;
}

return this.TransferFunction;
}

public void SetTransferFunction(JxlTransferFunction tf)
{
this.HaveGamma = false;
this.TransferFunction = tf;
}

public readonly float GetGamma()
{
if (!this.HaveGamma)
{
return 0.0f;
}

return this.Gamma * (1.0f / GammaMultiplier);
}

public void SetGamma(float newGamma)
{
if (newGamma is < 1.0f / MaxGamma or > 1.0f)
{
throw new InvalidOperationException($"Invalid gamma {newGamma}");
}

this.HaveGamma = false;

if (IsAlmostEqual(newGamma, 1.0f))
{
this.TransferFunction = JxlTransferFunction.Linear;
return;
}

if (IsAlmostEqual(newGamma, 1.0f / 2.6f))
{
this.TransferFunction = JxlTransferFunction.Dci;
return;
}

// Don't translate 0.45.. to kSRGB nor k709 - that might change pixel
// values because those curves also have a linear part.
this.HaveGamma = true;
this.Gamma = (uint)MathF.Round((float)(newGamma * GammaMultiplier));
this.TransferFunction = JxlTransferFunction.Unknown;
}

public readonly bool IsSame(JxlCustomTransferFunction other)
{
if (this.HaveGamma != other.HaveGamma)
{
return false;
}

if (this.HaveGamma)
{
return this.Gamma == other.Gamma;
}

return this.TransferFunction == other.TransferFunction;
}

private static bool IsAlmostEqual(float a, float b)
{
const float dist = 1e-3f;
return MathF.Abs(a - b) < dist;
}
}
53 changes: 53 additions & 0 deletions src/ImageSharp/Formats/Jxl/Cms/JxlCustomXy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

using SixLabors.ImageSharp.ColorProfiles;

namespace SixLabors.ImageSharp.Formats.Jxl.Cms;

/// <summary>
/// A serializable form of CieXyChromaticityCoordinates
/// </summary>
internal struct JxlCustomXy
{
private const uint Multiplier = 1000000;
private const float RoughLimit = 4.0f;
private const int Min = -0x200000;
private const int Max = 0x1FFFFF;

public int X { get; set; }

public int Y { get; set; }

public readonly CieXyChromaticityCoordinates GetValue() => new(
x: this.X * (1.0f / Multiplier),
y: this.Y * (1.0f / Multiplier));

public bool SetValue(CieXyChromaticityCoordinates xy)
{
bool ok = (Math.Abs(xy.X) < RoughLimit) && (Math.Abs(xy.Y) < RoughLimit);

if (!ok)
{
throw new InvalidOperationException("X or Y is out of bounds");
}

this.X = (int)MathF.Round((float)(xy.X * Multiplier));

if (this.X is < Min or > Max)
{
throw new InvalidOperationException("X is out of bounds");
}

this.Y = (int)MathF.Round((float)(xy.Y * Multiplier));

if (this.Y is < Min or > Max)
{
throw new InvalidOperationException("Y is out of bounds");
}

return true;
}

public readonly bool IsSame(CieXyChromaticityCoordinates other) => this.X == other.X && this.Y == other.Y;
}
27 changes: 27 additions & 0 deletions src/ImageSharp/Formats/Jxl/Cms/JxlPrimaries.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.

namespace SixLabors.ImageSharp.Formats.Jxl.Cms;

/// <summary>
/// JPEG XL primaries
/// </summary>
internal enum JxlPrimaries : byte
{
/// <summary>
/// Same as ITU-R BT.709
/// </summary>
SRgb = 1,

/// <summary>
/// Values encoded in separate fields
/// </summary>
Custom = 2,

/// <summary>
/// ITU-R BT.2020
/// </summary>
Bt2020 = 9,

P3 = 11,
}
13 changes: 13 additions & 0 deletions src/ImageSharp/Formats/Jxl/Cms/JxlRenderingIntent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

namespace SixLabors.ImageSharp.Formats.Jxl.Cms;

internal enum JxlRenderingIntent : byte
{
// Values match ICC sRGB encodings
Perceptual, // Good for photos, requires a profile with LUT
Relative, // Good for logos
Saturation, // Perhaps useful for CG with fully saturated colors
Absolute, // Leaves white point unchanged; good for proofing
}
45 changes: 45 additions & 0 deletions src/ImageSharp/Formats/Jxl/Cms/JxlTransferFunction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

namespace SixLabors.ImageSharp.Formats.Jxl.Cms;

/// <summary>
/// JPEG XL transfer function type
/// </summary>
internal enum JxlTransferFunction : byte
{
/// <summary>
/// ITU-R BT.709
/// </summary>
Bt709 = 1,

/// <summary>
/// Unknown transfer function
/// </summary>
Unknown = 2,

/// <summary>
/// Linear transfer function
/// </summary>
Linear = 8,

/// <summary>
/// sRGB
/// </summary>
SRgb = 13,

/// <summary>
/// From ITU-R BT.2100
/// </summary>
Pq = 16,

/// <summary>
/// From SMPTE RP 431-2 reference projector
/// </summary>
Dci = 17,

/// <summary>
/// From ITU-R BT.2100
/// </summary>
Hlg = 18,
}
Loading