From 6aa313f89589a04d3a5f7ed6665e3d27d5af2ef7 Mon Sep 17 00:00:00 2001 From: winscripter <142818255+winscripter@users.noreply.github.com> Date: Sat, 18 Jul 2026 16:56:36 +0400 Subject: [PATCH] Add matrices --- .../Jxl/Metadata/JxlOpsinInverseMatrix.cs | 5 +- .../Formats/Jxl/Processing/JxlLoopFilter.cs | 2 +- .../Formats/Jxl/Processing/JxlMatrix3x3.cs | 142 ++++++++++++++++++ .../Formats/Jxl/Processing/JxlMatrix3x3F.cs | 142 ++++++++++++++++++ 4 files changed, 288 insertions(+), 3 deletions(-) create mode 100644 src/ImageSharp/Formats/Jxl/Processing/JxlMatrix3x3.cs create mode 100644 src/ImageSharp/Formats/Jxl/Processing/JxlMatrix3x3F.cs diff --git a/src/ImageSharp/Formats/Jxl/Metadata/JxlOpsinInverseMatrix.cs b/src/ImageSharp/Formats/Jxl/Metadata/JxlOpsinInverseMatrix.cs index ccf2b2530..d0a14ffb4 100644 --- a/src/ImageSharp/Formats/Jxl/Metadata/JxlOpsinInverseMatrix.cs +++ b/src/ImageSharp/Formats/Jxl/Metadata/JxlOpsinInverseMatrix.cs @@ -1,7 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats.Jxl.IO; +using SixLabors.ImageSharp.Formats.Jxl.Fields; +using SixLabors.ImageSharp.Formats.Jxl.Processing; namespace SixLabors.ImageSharp.Formats.Jxl.Metadata; @@ -9,7 +10,7 @@ internal sealed class JxlOpsinInverseMatrix : IJxlFields { public bool AllDefault { get; set; } - public JxlMatrix3x3 InverseMatrix { get; set; } + public JxlMatrix3x3F InverseMatrix { get; set; } public InlineArray3 OpsinBiases { get; set; } diff --git a/src/ImageSharp/Formats/Jxl/Processing/JxlLoopFilter.cs b/src/ImageSharp/Formats/Jxl/Processing/JxlLoopFilter.cs index 01759a4d9..1a98138a3 100644 --- a/src/ImageSharp/Formats/Jxl/Processing/JxlLoopFilter.cs +++ b/src/ImageSharp/Formats/Jxl/Processing/JxlLoopFilter.cs @@ -237,7 +237,7 @@ internal sealed class JxlLoopFilter : IJxlFields { for (int iy = 0; iy < SigmaBorder; iy++) { - sigmaRow.Slice(offsetBefore + (SigmaPadding - 1 - iy) * sigmaStride, num) + sigmaRow.Slice(offsetBefore + ((SigmaPadding - 1 - iy) * sigmaStride), num) .CopyTo(sigmaRow.Slice(offsetBefore + ((SigmaPadding + iy) * sigmaStride))); } } diff --git a/src/ImageSharp/Formats/Jxl/Processing/JxlMatrix3x3.cs b/src/ImageSharp/Formats/Jxl/Processing/JxlMatrix3x3.cs new file mode 100644 index 000000000..a01e2a621 --- /dev/null +++ b/src/ImageSharp/Formats/Jxl/Processing/JxlMatrix3x3.cs @@ -0,0 +1,142 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.InteropServices; + +#pragma warning disable IDE0044 // Add readonly modifier +#pragma warning disable IDE0051 // Remove unused private members + +namespace SixLabors.ImageSharp.Formats.Jxl.Processing; + +internal struct JxlMatrix3x3 +{ + /// + /// Represents the matrix element at 0,0. + /// + private double e00; + + /// + /// Represents the matrix element at 0,1. + /// + private double e01; + + /// + /// Represents the matrix element at 0,2. + /// + private double e02; + + /// + /// Represents the matrix element at 1,0. + /// + private double e10; + + /// + /// Represents the matrix element at 1,1. + /// + private double e11; + + /// + /// Represents the matrix element at 1,2. + /// + private double e12; + + /// + /// Represents the matrix element at 2,0. + /// + private double e20; + + /// + /// Represents the matrix element at 2,1. + /// + private double e21; + + /// + /// Represents the matrix element at 2,2. + /// + private double e22; + + /// + /// Wraps all these values into a Span. + /// + /// A Span with all matrix elements. + public Span AsSpan() => MemoryMarshal.CreateSpan(ref this.e00, 9); + + /// + /// Wraps all these values into a ReadOnlySpan. + /// + /// A ReadOnlySpan with all matrix elements. + public ReadOnlySpan AsReadOnlySpan() => MemoryMarshal.CreateReadOnlySpan(ref this.e00, 9); + + public static void Multiply(in JxlMatrix3x3 a, in JxlMatrix3x3 b, ref JxlMatrix3x3 c) + { + ReadOnlySpan spanA = a.AsReadOnlySpan(); + ReadOnlySpan spanB = b.AsReadOnlySpan(); + Span spanC = c.AsSpan(); + + for (int row = 0; row < 3; row++) + { + int row3 = row * 3; + for (int col = 0; col < 3; col++) + { + double sum = 0d; + for (int k = 0; k < 3; k++) + { + sum += spanA[row3 + k] * spanB[(k * 3) + col]; + } + + spanC[row3 + col] = sum; + } + } + } + + public static void Multiply(in JxlMatrix3x3 a, ReadOnlySpan b, Span c) + { + ReadOnlySpan spanA = a.AsReadOnlySpan(); + + for (int row = 0; row < 3; row++) + { + double sum = 0f; + int row3 = row * 3; + for (int col = 0; col < 3; col++) + { + sum += spanA[row3 + col] * b[col]; + } + + c[row] = sum; + } + } + + public static bool Invert(ref JxlMatrix3x3 matrix) + { + ReadOnlySpan m = matrix.AsReadOnlySpan(); + Span temp = + [ + ((double)m[4] * m[8]) - ((double)m[5] * m[7]), + ((double)m[2] * m[7]) - ((double)m[1] * m[8]), + ((double)m[1] * m[5]) - ((double)m[2] * m[4]), + ((double)m[5] * m[6]) - ((double)m[3] * m[8]), + ((double)m[0] * m[8]) - ((double)m[2] * m[6]), + ((double)m[2] * m[3]) - ((double)m[0] * m[5]), + ((double)m[3] * m[7]) - ((double)m[4] * m[6]), + ((double)m[1] * m[6]) - ((double)m[0] * m[7]), + ((double)m[0] * m[4]) - ((double)m[1] * m[3]), + ]; + + double det = (m[0] * temp[0]) + (m[1] * temp[3]) + (m[2] * temp[6]); + + if (Math.Abs(det) < 1e-10) + { + return false; + } + + double idet = 1.0 / det; + Span spanM = matrix.AsSpan(); + + for (int i = 0; i < 9; i++) + { + spanM[i] = (double)(temp[i] * idet); + } + + return true; + } +} diff --git a/src/ImageSharp/Formats/Jxl/Processing/JxlMatrix3x3F.cs b/src/ImageSharp/Formats/Jxl/Processing/JxlMatrix3x3F.cs new file mode 100644 index 000000000..fda6282e0 --- /dev/null +++ b/src/ImageSharp/Formats/Jxl/Processing/JxlMatrix3x3F.cs @@ -0,0 +1,142 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.InteropServices; + +#pragma warning disable IDE0044 // Add readonly modifier +#pragma warning disable IDE0051 // Remove unused private members + +namespace SixLabors.ImageSharp.Formats.Jxl.Processing; + +internal struct JxlMatrix3x3F +{ + /// + /// Represents the matrix element at 0,0. + /// + private float e00; + + /// + /// Represents the matrix element at 0,1. + /// + private float e01; + + /// + /// Represents the matrix element at 0,2. + /// + private float e02; + + /// + /// Represents the matrix element at 1,0. + /// + private float e10; + + /// + /// Represents the matrix element at 1,1. + /// + private float e11; + + /// + /// Represents the matrix element at 1,2. + /// + private float e12; + + /// + /// Represents the matrix element at 2,0. + /// + private float e20; + + /// + /// Represents the matrix element at 2,1. + /// + private float e21; + + /// + /// Represents the matrix element at 2,2. + /// + private float e22; + + /// + /// Wraps all these values into a Span. + /// + /// A Span with all matrix elements. + public Span AsSpan() => MemoryMarshal.CreateSpan(ref this.e00, 9); + + /// + /// Wraps all these values into a ReadOnlySpan. + /// + /// A ReadOnlySpan with all matrix elements. + public ReadOnlySpan AsReadOnlySpan() => MemoryMarshal.CreateReadOnlySpan(ref this.e00, 9); + + public static void Multiply(in JxlMatrix3x3F a, in JxlMatrix3x3F b, ref JxlMatrix3x3F c) + { + ReadOnlySpan spanA = a.AsReadOnlySpan(); + ReadOnlySpan spanB = b.AsReadOnlySpan(); + Span spanC = c.AsSpan(); + + for (int row = 0; row < 3; row++) + { + int row3 = row * 3; + for (int col = 0; col < 3; col++) + { + float sum = 0f; + for (int k = 0; k < 3; k++) + { + sum += spanA[row3 + k] * spanB[(k * 3) + col]; + } + + spanC[row3 + col] = sum; + } + } + } + + public static void Multiply(in JxlMatrix3x3F a, ReadOnlySpan b, Span c) + { + ReadOnlySpan spanA = a.AsReadOnlySpan(); + + for (int row = 0; row < 3; row++) + { + float sum = 0f; + int row3 = row * 3; + for (int col = 0; col < 3; col++) + { + sum += spanA[row3 + col] * b[col]; + } + + c[row] = sum; + } + } + + public static bool Invert(ref JxlMatrix3x3F matrix) + { + ReadOnlySpan m = matrix.AsReadOnlySpan(); + Span temp = + [ + ((double)m[4] * m[8]) - ((double)m[5] * m[7]), + ((double)m[2] * m[7]) - ((double)m[1] * m[8]), + ((double)m[1] * m[5]) - ((double)m[2] * m[4]), + ((double)m[5] * m[6]) - ((double)m[3] * m[8]), + ((double)m[0] * m[8]) - ((double)m[2] * m[6]), + ((double)m[2] * m[3]) - ((double)m[0] * m[5]), + ((double)m[3] * m[7]) - ((double)m[4] * m[6]), + ((double)m[1] * m[6]) - ((double)m[0] * m[7]), + ((double)m[0] * m[4]) - ((double)m[1] * m[3]), + ]; + + double det = (m[0] * temp[0]) + (m[1] * temp[3]) + (m[2] * temp[6]); + + if (Math.Abs(det) < 1e-10) + { + return false; + } + + double idet = 1.0 / det; + Span spanM = matrix.AsSpan(); + + for (int i = 0; i < 9; i++) + { + spanM[i] = (float)(temp[i] * idet); + } + + return true; + } +}