Browse Source

Finish inverse RCT

pull/3153/head
winscripter 1 week ago
parent
commit
093d84612c
  1. 83
      src/ImageSharp/Formats/Jxl/Processing/Modular/Transforms/JxlRct.cs
  2. 28
      src/ImageSharp/Formats/Jxl/Processing/Modular/Transforms/JxlTransform.cs

83
src/ImageSharp/Formats/Jxl/Processing/Modular/Transforms/JxlRct.cs

@ -10,10 +10,22 @@ namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Modular.Transforms;
/// </summary>
internal static class JxlRct
{
public static void InverseRctRow(int transformType, Span<int> in0, Span<int> in1, Span<int> in2, Span<int> out0, Span<int> out1, Span<int> out2, int width)
/// <summary>
/// Performs Inverse Reversible Color Transform (RCT) on one row.
/// </summary>
/// <param name="transformType">The kind of RCT.</param>
/// <param name="in0">Input Y</param>
/// <param name="in1">Input Co</param>
/// <param name="in2">Input Cg</param>
/// <param name="out0">Output R</param>
/// <param name="out1">Output G</param>
/// <param name="out2">Output B</param>
private static void InverseRctRow(int transformType, Span<int> in0, Span<int> in1, Span<int> in2, Span<int> out0, Span<int> out1, Span<int> out2)
{
DebugGuard.MustBeBetweenOrEqualTo(transformType, 0, 6, nameof(transformType));
int width = in0.Length; // All input & output channels have equal widths
int second = transformType >> 1;
int third = transformType & 1;
@ -112,4 +124,73 @@ internal static class JxlRct
}
}
}
/// <summary>
/// Performs Inverse Reversible Color Transform (RCT) on an entire
/// image.
/// </summary>
/// <param name="configuration">
/// The configuration is used to access maximum degree of parallelism.
/// </param>
/// <param name="img">
/// Image to compute inverse RCT.
/// </param>
/// <param name="beginC">
/// Offset of the color channel for Y, Co, Cg.
/// </param>
/// <param name="rctType">
/// Type of Reversible Color Transform
/// </param>
/// <exception cref="InvalidOperationException">
/// Invoked when RCT/permutation is invalid.
/// </exception>
public static void InverseRct(Configuration configuration, JxlModularImage img, int beginC, int rctType)
{
JxlTransform.CheckEqualChannels(img, beginC, beginC + 2);
int m = beginC;
JxlModularChannel c0 = img.Channels[m + 0];
int w = c0.Width;
int h = c0.Height;
if (rctType == 0)
{
// No-op
return;
}
int permutation = rctType / 7;
if (permutation >= 7)
{
throw new InvalidOperationException("Permutation must be <= 6");
}
int custom = rctType % 7;
if (custom == 0)
{
// Permute-only.
JxlModularChannel ch0 = img.Channels[m];
JxlModularChannel ch1 = img.Channels[m + 1];
JxlModularChannel ch2 = img.Channels[m + 2];
img.Channels[m + (permutation % 3)] = ch0;
img.Channels[m + ((permutation + 1 + (permutation / 3)) % 3)] = ch1;
img.Channels[m + ((permutation + 2 - (permutation / 3)) % 3)] = ch2;
return;
}
_ = Parallel.For(0, configuration.MaxDegreeOfParallelism, y =>
{
Span<int> in0 = img.Channels[m].GetRow(y);
Span<int> in1 = img.Channels[m + 1].GetRow(y);
Span<int> in2 = img.Channels[m + 2].GetRow(y);
Span<int> out0 = img.Channels[m + (permutation % 3)].GetRow(y);
Span<int> out1 = img.Channels[m + ((permutation + 1 + (permutation / 3)) % 3)].GetRow(y);
Span<int> out2 = img.Channels[m + ((permutation + 2 - (permutation / 3)) % 3)].GetRow(y);
InverseRctRow(custom, in0, in1, in2, out0, out1, out2);
});
}
}

28
src/ImageSharp/Formats/Jxl/Processing/Modular/Transforms/JxlTransform.cs

@ -8,4 +8,32 @@ namespace SixLabors.ImageSharp.Formats.Jxl.Processing.Modular.Transforms;
internal sealed class JxlTransform : IJxlFields
{
public bool Visit(JxlVisitor visitor) => throw new NotImplementedException();
public static void CheckEqualChannels(JxlModularImage image, int c1, int c2)
{
int channelsCount = image.Channels.Count;
if (c1 > channelsCount || c2 >= channelsCount || c2 < c1)
{
throw new InvalidOperationException($"Invalid channel range: {c1}..{c2} (there are only {channelsCount} channels)");
}
if (c1 < image.NbMetaChannels && c2 >= image.NbMetaChannels)
{
throw new InvalidOperationException("Invalid: transforming mix of meta and nonmeta");
}
JxlModularChannel ch1 = image.Channels[c1];
for (int c = c1 + 1; c <= c2; c++)
{
JxlModularChannel ch2 = image.Channels[c];
if (ch1.Width != ch2.Width ||
ch1.Height != ch2.Height ||
ch1.HorizontalShift != ch2.HorizontalShift ||
ch1.VerticalShift != ch2.VerticalShift)
{
throw new InvalidOperationException($"Channel {c} is not equal");
}
}
}
}

Loading…
Cancel
Save