diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykOperator.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykOperator.cs
new file mode 100644
index 000000000..48281c34a
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykOperator.cs
@@ -0,0 +1,245 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+using System.Runtime.CompilerServices;
+using System.Runtime.Intrinsics;
+using SixLabors.ImageSharp.Metadata.Profiles.Icc;
+
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components;
+
+internal abstract partial class JpegColorConverterBase
+{
+ ///
+ /// Implements inverted JPEG CMYK conversion for scalar and SIMD lanes.
+ ///
+ internal readonly struct CmykOperator : IJpegColorConverterOperator
+ {
+ ///
+ public static JpegColorSpace ColorSpace => JpegColorSpace.Cmyk;
+
+ ///
+ public static int ComponentCount => 4;
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ConvertToRgb(
+ ref float c0,
+ ref float c1,
+ ref float c2,
+ float c3,
+ float maximumValue,
+ float halfValue,
+ float scale)
+ {
+ // Adobe-style CMYK stores inverted component samples. Multiplying K by scale twice folds the
+ // two sample-domain divisions into one factor before it modulates the C, M, and Y planes.
+ float scaledK = c3 * scale * scale;
+ c0 *= scaledK;
+ c1 *= scaledK;
+ c2 *= scaledK;
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ConvertToRgb(
+ ref Vector128 c0,
+ ref Vector128 c1,
+ ref Vector128 c2,
+ Vector128 c3,
+ Vector128 maximumValue,
+ Vector128 halfValue,
+ Vector128 scale)
+ {
+ // Each K lane supplies the common modulation factor for the corresponding C, M, and Y lanes.
+ Vector128 scaledK = c3 * scale * scale;
+ c0 *= scaledK;
+ c1 *= scaledK;
+ c2 *= scaledK;
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ConvertToRgb(
+ ref Vector256 c0,
+ ref Vector256 c1,
+ ref Vector256 c2,
+ Vector256 c3,
+ Vector256 maximumValue,
+ Vector256 halfValue,
+ Vector256 scale)
+ {
+ // Eight independent CMYK samples remain lane-aligned throughout the modulation.
+ Vector256 scaledK = c3 * scale * scale;
+ c0 *= scaledK;
+ c1 *= scaledK;
+ c2 *= scaledK;
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ConvertToRgb(
+ ref Vector512 c0,
+ ref Vector512 c1,
+ ref Vector512 c2,
+ Vector512 c3,
+ Vector512 maximumValue,
+ Vector512 halfValue,
+ Vector512 scale)
+ {
+ // Sixteen independent CMYK samples remain lane-aligned throughout the modulation.
+ Vector512 scaledK = c3 * scale * scale;
+ c0 *= scaledK;
+ c1 *= scaledK;
+ c2 *= scaledK;
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ConvertFromRgb(
+ float r,
+ float g,
+ float b,
+ float maximumValue,
+ float halfValue,
+ float scale,
+ out float c0,
+ out float c1,
+ out float c2,
+ out float c3)
+ {
+ float c = maximumValue - r;
+ float m = maximumValue - g;
+ float y = maximumValue - b;
+ float k = MathF.Min(c, MathF.Min(m, y));
+
+ // Pure black makes the chromatic divisor zero. In that case chromatic ink is defined as zero;
+ // otherwise remove K and normalize the remaining C, M, and Y contributions.
+ if (k >= maximumValue)
+ {
+ c = 0;
+ m = 0;
+ y = 0;
+ }
+ else
+ {
+ // The same remaining range normalizes every chromatic channel. Computing its reciprocal once
+ // replaces three divisions with one division and three multiplies.
+ float reciprocal = 1F / (maximumValue - k);
+ c = (c - k) * reciprocal;
+ m = (m - k) * reciprocal;
+ y = (y - k) * reciprocal;
+ }
+
+ // JPEG CMYK is inverted, including K, so normalized chromatic values are reflected around max.
+ c0 = maximumValue - (c * maximumValue);
+ c1 = maximumValue - (m * maximumValue);
+ c2 = maximumValue - (y * maximumValue);
+ c3 = maximumValue - k;
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ConvertFromRgb(
+ Vector128 r,
+ Vector128 g,
+ Vector128 b,
+ Vector128 maximumValue,
+ Vector128 halfValue,
+ Vector128 scale,
+ out Vector128 c0,
+ out Vector128 c1,
+ out Vector128 c2,
+ out Vector128 c3)
+ {
+ Vector128 c = maximumValue - r;
+ Vector128 m = maximumValue - g;
+ Vector128 y = maximumValue - b;
+ Vector128 k = Vector128.Min(c, Vector128.Min(m, y));
+
+ // The all-bits mask clears the undefined zero-divisor result for pure-black lanes without a branch.
+ Vector128 nonBlack = ~Vector128.Equals(k, maximumValue);
+ Vector128 reciprocal = Vector128.One / (maximumValue - k);
+ c = ((c - k) * reciprocal) & nonBlack;
+ m = ((m - k) * reciprocal) & nonBlack;
+ y = ((y - k) * reciprocal) & nonBlack;
+
+ c0 = maximumValue - (c * maximumValue);
+ c1 = maximumValue - (m * maximumValue);
+ c2 = maximumValue - (y * maximumValue);
+ c3 = maximumValue - k;
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ConvertFromRgb(
+ Vector256 r,
+ Vector256 g,
+ Vector256 b,
+ Vector256 maximumValue,
+ Vector256 halfValue,
+ Vector256 scale,
+ out Vector256 c0,
+ out Vector256 c1,
+ out Vector256 c2,
+ out Vector256 c3)
+ {
+ Vector256 c = maximumValue - r;
+ Vector256 m = maximumValue - g;
+ Vector256 y = maximumValue - b;
+ Vector256 k = Vector256.Min(c, Vector256.Min(m, y));
+
+ // Masking preserves lane independence when a vector mixes pure black with chromatic pixels.
+ Vector256 nonBlack = ~Vector256.Equals(k, maximumValue);
+ Vector256 reciprocal = Vector256.One / (maximumValue - k);
+ c = ((c - k) * reciprocal) & nonBlack;
+ m = ((m - k) * reciprocal) & nonBlack;
+ y = ((y - k) * reciprocal) & nonBlack;
+
+ c0 = maximumValue - (c * maximumValue);
+ c1 = maximumValue - (m * maximumValue);
+ c2 = maximumValue - (y * maximumValue);
+ c3 = maximumValue - k;
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ConvertFromRgb(
+ Vector512 r,
+ Vector512 g,
+ Vector512 b,
+ Vector512 maximumValue,
+ Vector512 halfValue,
+ Vector512 scale,
+ out Vector512 c0,
+ out Vector512 c1,
+ out Vector512 c2,
+ out Vector512 c3)
+ {
+ Vector512 c = maximumValue - r;
+ Vector512 m = maximumValue - g;
+ Vector512 y = maximumValue - b;
+ Vector512 k = Vector512.Min(c, Vector512.Min(m, y));
+
+ // AVX-512 still uses a full floating-point mask value here because bitwise clearing exactly matches
+ // the narrower operator semantics and lets the JIT select the most suitable native instructions.
+ Vector512 nonBlack = ~Vector512.Equals(k, maximumValue);
+ Vector512 reciprocal = Vector512.One / (maximumValue - k);
+ c = ((c - k) * reciprocal) & nonBlack;
+ m = ((m - k) * reciprocal) & nonBlack;
+ y = ((y - k) * reciprocal) & nonBlack;
+
+ c0 = maximumValue - (c * maximumValue);
+ c1 = maximumValue - (m * maximumValue);
+ c2 = maximumValue - (y * maximumValue);
+ c3 = maximumValue - k;
+ }
+
+ ///
+ public static void ConvertToRgbInPlaceWithIcc(
+ Configuration configuration,
+ IccProfile profile,
+ in ComponentValues values,
+ float maximumValue)
+ => CmykScalar.ConvertToRgbInPlaceWithIcc(configuration, profile, values, maximumValue);
+ }
+}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleOperator.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleOperator.cs
new file mode 100644
index 000000000..2ac827da7
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleOperator.cs
@@ -0,0 +1,203 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+using System.Runtime.CompilerServices;
+using System.Runtime.Intrinsics;
+using SixLabors.ImageSharp.Common.Helpers;
+using SixLabors.ImageSharp.Metadata.Profiles.Icc;
+
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components;
+
+internal abstract partial class JpegColorConverterBase
+{
+ ///
+ /// Implements grayscale expansion and RGB luminance reduction for scalar and SIMD lanes.
+ ///
+ internal readonly struct GrayScaleOperator : IJpegColorConverterOperator
+ {
+ ///
+ public static JpegColorSpace ColorSpace => JpegColorSpace.Grayscale;
+
+ ///
+ public static int ComponentCount => 1;
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ConvertToRgb(
+ ref float c0,
+ ref float c1,
+ ref float c2,
+ float c3,
+ float maximumValue,
+ float halfValue,
+ float scale)
+ {
+ // JPEG stores luminance in the integer sample domain. Normalize it once, then duplicate the
+ // same value into all three RGB planes. Keeping it local also prevents potentially aliasing
+ // byref stores from forcing the JIT to reload c0 between assignments.
+ float luminance = c0 * scale;
+ c0 = luminance;
+ c1 = luminance;
+ c2 = luminance;
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ConvertToRgb(
+ ref Vector128 c0,
+ ref Vector128 c1,
+ ref Vector128 c2,
+ Vector128 c3,
+ Vector128 maximumValue,
+ Vector128 halfValue,
+ Vector128 scale)
+ {
+ // Each XMM lane is one independent luminance sample. Reusing the normalized vector for R, G,
+ // and B avoids recomputing the scale and keeps it live across potentially aliasing byref stores.
+ Vector128 luminance = c0 * scale;
+ c0 = luminance;
+ c1 = luminance;
+ c2 = luminance;
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ConvertToRgb(
+ ref Vector256 c0,
+ ref Vector256 c1,
+ ref Vector256 c2,
+ Vector256 c3,
+ Vector256 maximumValue,
+ Vector256 halfValue,
+ Vector256 scale)
+ {
+ // Eight luminance samples occupy the YMM lanes. The local retains the normalized vector across
+ // all three output stores even when the destination planes alias.
+ Vector256 luminance = c0 * scale;
+ c0 = luminance;
+ c1 = luminance;
+ c2 = luminance;
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ConvertToRgb(
+ ref Vector512 c0,
+ ref Vector512 c1,
+ ref Vector512 c2,
+ Vector512 c3,
+ Vector512 maximumValue,
+ Vector512 halfValue,
+ Vector512 scale)
+ {
+ // Sixteen luminance samples occupy the ZMM lanes. The local retains the normalized vector across
+ // all three output stores without shuffles, interleaving, or source reloads.
+ Vector512 luminance = c0 * scale;
+ c0 = luminance;
+ c1 = luminance;
+ c2 = luminance;
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ConvertFromRgb(
+ float r,
+ float g,
+ float b,
+ float maximumValue,
+ float halfValue,
+ float scale,
+ out float c0,
+ out float c1,
+ out float c2,
+ out float c3)
+ {
+ // Rec.601 luma weights operate directly in the encoder sample domain. Only c0 is stored for a
+ // one-component model; the remaining out values exist solely to satisfy the common operator shape.
+ c0 = (0.299F * r) + (0.587F * g) + (0.114F * b);
+ c1 = 0;
+ c2 = 0;
+ c3 = 0;
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ConvertFromRgb(
+ Vector128 r,
+ Vector128 g,
+ Vector128 b,
+ Vector128 maximumValue,
+ Vector128 halfValue,
+ Vector128 scale,
+ out Vector128 c0,
+ out Vector128 c1,
+ out Vector128 c2,
+ out Vector128 c3)
+ {
+ // The nested estimate gives each pixel the same multiply-add grouping as the scalar Rec.601 formula.
+ c0 = Vector128_.MultiplyAddEstimate(
+ Vector128.Create(0.299F),
+ r,
+ Vector128_.MultiplyAddEstimate(Vector128.Create(0.587F), g, Vector128.Create(0.114F) * b));
+ c1 = default;
+ c2 = default;
+ c3 = default;
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ConvertFromRgb(
+ Vector256 r,
+ Vector256 g,
+ Vector256 b,
+ Vector256 maximumValue,
+ Vector256 halfValue,
+ Vector256 scale,
+ out Vector256 c0,
+ out Vector256 c1,
+ out Vector256 c2,
+ out Vector256 c3)
+ {
+ // YMM lanes evaluate the same Rec.601 equation independently, with no horizontal lane reduction.
+ c0 = Vector256_.MultiplyAddEstimate(
+ Vector256.Create(0.299F),
+ r,
+ Vector256_.MultiplyAddEstimate(Vector256.Create(0.587F), g, Vector256.Create(0.114F) * b));
+ c1 = default;
+ c2 = default;
+ c3 = default;
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ConvertFromRgb(
+ Vector512 r,
+ Vector512 g,
+ Vector512 b,
+ Vector512 maximumValue,
+ Vector512 halfValue,
+ Vector512 scale,
+ out Vector512 c0,
+ out Vector512 c1,
+ out Vector512 c2,
+ out Vector512 c3)
+ {
+ // ZMM lanes retain the same arithmetic order as narrower paths so only SIMD width changes.
+ c0 = Vector512_.MultiplyAddEstimate(
+ Vector512.Create(0.299F),
+ r,
+ Vector512_.MultiplyAddEstimate(Vector512.Create(0.587F), g, Vector512.Create(0.114F) * b));
+ c1 = default;
+ c2 = default;
+ c3 = default;
+ }
+
+ ///
+ public static void ConvertToRgbInPlaceWithIcc(
+ Configuration configuration,
+ IccProfile profile,
+ in ComponentValues values,
+ float maximumValue)
+ => GrayScaleScalar.ConvertToRgbInPlaceWithIcc(configuration, profile, values, maximumValue);
+ }
+}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.Operator.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.Operator.cs
new file mode 100644
index 000000000..be9cedcb0
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.Operator.cs
@@ -0,0 +1,594 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using SixLabors.ImageSharp.Common.Helpers;
+using SixLabors.ImageSharp.Metadata.Profiles.Icc;
+
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components;
+
+internal abstract partial class JpegColorConverterBase
+{
+ ///
+ /// Defines the color-model-specific arithmetic used by .
+ ///
+ ///
+ /// Each overload describes the same lane-wise transform. The generic traversal selects the widest
+ /// available overload and the JIT resolves these static interface calls for each closed converter type.
+ ///
+ internal interface IJpegColorConverterOperator
+ {
+ ///
+ /// Gets the JPEG color space handled by the operator.
+ ///
+ static abstract JpegColorSpace ColorSpace { get; }
+
+ ///
+ /// Gets the number of component planes used by the color space.
+ ///
+ static abstract int ComponentCount { get; }
+
+ ///
+ /// Converts one JPEG sample to normalized RGB.
+ ///
+ /// The first component, replaced by red.
+ /// The second component, replaced by green.
+ /// The third component, replaced by blue.
+ /// The fourth component, or zero for a three-component color space.
+ /// The maximum component value for the configured precision.
+ /// The midpoint component value for the configured precision.
+ /// The reciprocal of .
+ static abstract void ConvertToRgb(
+ ref float c0,
+ ref float c1,
+ ref float c2,
+ float c3,
+ float maximumValue,
+ float halfValue,
+ float scale);
+
+ ///
+ /// Converts four JPEG samples to normalized RGB.
+ ///
+ /// The first component lanes, replaced by red.
+ /// The second component lanes, replaced by green.
+ /// The third component lanes, replaced by blue.
+ /// The fourth component lanes, or zero for a three-component color space.
+ /// The maximum component value for the configured precision.
+ /// The midpoint component value for the configured precision.
+ /// The reciprocal of in every lane.
+ static abstract void ConvertToRgb(
+ ref Vector128 c0,
+ ref Vector128 c1,
+ ref Vector128 c2,
+ Vector128 c3,
+ Vector128 maximumValue,
+ Vector128 halfValue,
+ Vector128 scale);
+
+ ///
+ /// Converts eight JPEG samples to normalized RGB.
+ ///
+ /// The first component lanes, replaced by red.
+ /// The second component lanes, replaced by green.
+ /// The third component lanes, replaced by blue.
+ /// The fourth component lanes, or zero for a three-component color space.
+ /// The maximum component value for the configured precision.
+ /// The midpoint component value for the configured precision.
+ /// The reciprocal of in every lane.
+ static abstract void ConvertToRgb(
+ ref Vector256 c0,
+ ref Vector256 c1,
+ ref Vector256 c2,
+ Vector256 c3,
+ Vector256 maximumValue,
+ Vector256 halfValue,
+ Vector256 scale);
+
+ ///
+ /// Converts sixteen JPEG samples to normalized RGB.
+ ///
+ /// The first component lanes, replaced by red.
+ /// The second component lanes, replaced by green.
+ /// The third component lanes, replaced by blue.
+ /// The fourth component lanes, or zero for a three-component color space.
+ /// The maximum component value for the configured precision.
+ /// The midpoint component value for the configured precision.
+ /// The reciprocal of in every lane.
+ static abstract void ConvertToRgb(
+ ref Vector512 c0,
+ ref Vector512 c1,
+ ref Vector512 c2,
+ Vector512 c3,
+ Vector512 maximumValue,
+ Vector512 halfValue,
+ Vector512 scale);
+
+ ///
+ /// Converts one RGB sample to JPEG components.
+ ///
+ /// The red value.
+ /// The green value.
+ /// The blue value.
+ /// The maximum component value for the configured precision.
+ /// The midpoint component value for the configured precision.
+ /// The reciprocal of .
+ /// The first converted component.
+ /// The second converted component.
+ /// The third converted component.
+ /// The fourth converted component, if used.
+ static abstract void ConvertFromRgb(
+ float r,
+ float g,
+ float b,
+ float maximumValue,
+ float halfValue,
+ float scale,
+ out float c0,
+ out float c1,
+ out float c2,
+ out float c3);
+
+ ///
+ /// Converts four RGB samples to JPEG components.
+ ///
+ /// The red lanes.
+ /// The green lanes.
+ /// The blue lanes.
+ /// The maximum component value for the configured precision.
+ /// The midpoint component value for the configured precision.
+ /// The reciprocal of in every lane.
+ /// The first converted component lanes.
+ /// The second converted component lanes.
+ /// The third converted component lanes.
+ /// The fourth converted component lanes, if used.
+ static abstract void ConvertFromRgb(
+ Vector128 r,
+ Vector128 g,
+ Vector128 b,
+ Vector128 maximumValue,
+ Vector128 halfValue,
+ Vector128 scale,
+ out Vector128 c0,
+ out Vector128 c1,
+ out Vector128 c2,
+ out Vector128 c3);
+
+ ///
+ /// Converts eight RGB samples to JPEG components.
+ ///
+ /// The red lanes.
+ /// The green lanes.
+ /// The blue lanes.
+ /// The maximum component value for the configured precision.
+ /// The midpoint component value for the configured precision.
+ /// The reciprocal of in every lane.
+ /// The first converted component lanes.
+ /// The second converted component lanes.
+ /// The third converted component lanes.
+ /// The fourth converted component lanes, if used.
+ static abstract void ConvertFromRgb(
+ Vector256 r,
+ Vector256 g,
+ Vector256 b,
+ Vector256 maximumValue,
+ Vector256 halfValue,
+ Vector256 scale,
+ out Vector256 c0,
+ out Vector256 c1,
+ out Vector256 c2,
+ out Vector256 c3);
+
+ ///
+ /// Converts sixteen RGB samples to JPEG components.
+ ///
+ /// The red lanes.
+ /// The green lanes.
+ /// The blue lanes.
+ /// The maximum component value for the configured precision.
+ /// The midpoint component value for the configured precision.
+ /// The reciprocal of in every lane.
+ /// The first converted component lanes.
+ /// The second converted component lanes.
+ /// The third converted component lanes.
+ /// The fourth converted component lanes, if used.
+ static abstract void ConvertFromRgb(
+ Vector512 r,
+ Vector512 g,
+ Vector512 b,
+ Vector512 maximumValue,
+ Vector512 halfValue,
+ Vector512 scale,
+ out Vector512 c0,
+ out Vector512 c1,
+ out Vector512 c2,
+ out Vector512 c3);
+
+ ///
+ /// Converts JPEG component values to RGB using the supplied ICC profile.
+ ///
+ /// The configuration used to allocate temporary storage.
+ /// The source ICC profile.
+ /// The component values to convert.
+ /// The maximum component value for the configured precision.
+ static abstract void ConvertToRgbInPlaceWithIcc(
+ Configuration configuration,
+ IccProfile profile,
+ in ComponentValues values,
+ float maximumValue);
+ }
+
+ ///
+ /// Converts a JPEG color model using a single operator-driven traversal for all SIMD widths.
+ ///
+ /// The color-model-specific arithmetic.
+ internal sealed class JpegColorConverter : JpegColorConverterBase
+ where TOperator : struct, IJpegColorConverterOperator
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The precision in bits.
+ public JpegColorConverter(int precision)
+ : base(TOperator.ColorSpace, precision)
+ {
+ }
+
+ ///
+ public override bool IsAvailable => true;
+
+ ///
+ public override int ElementsPerBatch
+ => Vector512.IsHardwareAccelerated
+ ? Vector512.Count
+ : Vector256.IsHardwareAccelerated
+ ? Vector256.Count
+ : Vector128.IsHardwareAccelerated
+ ? Vector128.Count
+ : 1;
+
+ ///
+ public override void ConvertToRgbInPlace(in ComponentValues values)
+ {
+ // JPEG component processors own equally sized planar buffers. Capturing their first elements
+ // as byrefs lets every width share the same offset without introducing Span bounds checks in
+ // the hot loops. Component3 may be empty; its byref is only dereferenced for four-component operators.
+ ref float c0Base = ref MemoryMarshal.GetReference(values.Component0);
+ ref float c1Base = ref MemoryMarshal.GetReference(values.Component1);
+ ref float c2Base = ref MemoryMarshal.GetReference(values.Component2);
+ ref float c3Base = ref MemoryMarshal.GetReference(values.Component3);
+
+ int length = values.Component0.Length;
+ int i = 0;
+ float scale = 1F / this.MaximumValue;
+
+ // Descending widths keep one traversal while allowing an AVX-512 machine to process
+ // an eight-pixel JPEG block with AVX2 rather than sending the entire block to scalar code.
+ if (Vector512.IsHardwareAccelerated)
+ {
+ // Subtracting the lane count turns the loop condition into a single signed comparison.
+ // A negative value naturally skips this width, and i <= end proves every unaligned
+ // 64-byte reinterpretation remains entirely inside its component buffer.
+ int oneVectorFromEnd = length - Vector512.Count;
+
+ if (i <= oneVectorFromEnd)
+ {
+ // Precision-derived values are broadcast only when this width has work. Keeping them outside
+ // the loop avoids repeated setup without penalizing rows handled entirely by narrower widths.
+ Vector512 maximumValue = Vector512.Create(this.MaximumValue);
+ Vector512 halfValue = Vector512.Create(this.HalfValue);
+ Vector512 scaleVector = Vector512.Create(scale);
+
+ for (; i <= oneVectorFromEnd; i += Vector512.Count)
+ {
+ ref Vector512 c0 = ref Unsafe.As>(ref Unsafe.Add(ref c0Base, i));
+ ref Vector512 c1 = ref Unsafe.As>(ref Unsafe.Add(ref c1Base, i));
+ ref Vector512 c2 = ref Unsafe.As>(ref Unsafe.Add(ref c2Base, i));
+
+ // ComponentCount is a static property on the closed operator type, so the JIT removes
+ // this choice. Three-component models never dereference the empty Component3 byref.
+ Vector512 c3 = TOperator.ComponentCount == 4
+ ? Unsafe.As>(ref Unsafe.Add(ref c3Base, i))
+ : default;
+
+ // c0-c2 alias the planar source vectors and are replaced in place with normalized RGB.
+ // c3 is passed by value because the fourth JPEG component must remain unchanged.
+ TOperator.ConvertToRgb(ref c0, ref c1, ref c2, c3, maximumValue, halfValue, scaleVector);
+ }
+ }
+ }
+
+ if (Vector256.IsHardwareAccelerated)
+ {
+ // The shared offset continues where AVX-512 stopped. At this point fewer than sixteen
+ // samples remain, so this stage consumes the complete eight-sample remainder when present.
+ int oneVectorFromEnd = length - Vector256.Count;
+
+ if (i <= oneVectorFromEnd)
+ {
+ // YMM precision state is materialized only for an eight-sample remainder or an AVX2-only loop.
+ Vector256 maximumValue = Vector256.Create(this.MaximumValue);
+ Vector256 halfValue = Vector256.Create(this.HalfValue);
+ Vector256 scaleVector = Vector256.Create(scale);
+
+ for (; i <= oneVectorFromEnd; i += Vector256.Count)
+ {
+ ref Vector256 c0 = ref Unsafe.As>(ref Unsafe.Add(ref c0Base, i));
+ ref Vector256 c1 = ref Unsafe.As>(ref Unsafe.Add(ref c1Base, i));
+ ref Vector256 c2 = ref Unsafe.As>(ref Unsafe.Add(ref c2Base, i));
+
+ // The closed operator makes this a compile-time color-model choice, not a per-vector
+ // runtime abstraction or interface dispatch.
+ Vector256 c3 = TOperator.ComponentCount == 4
+ ? Unsafe.As>(ref Unsafe.Add(ref c3Base, i))
+ : default;
+
+ TOperator.ConvertToRgb(ref c0, ref c1, ref c2, c3, maximumValue, halfValue, scaleVector);
+ }
+ }
+ }
+
+ if (Vector128.IsHardwareAccelerated)
+ {
+ // SSE/AdvSimd handles the final four complete samples. This also gives non-AVX machines
+ // the same traversal without duplicating the control flow for another register width.
+ int oneVectorFromEnd = length - Vector128.Count;
+
+ if (i <= oneVectorFromEnd)
+ {
+ // XMM state is likewise created only when four samples remain for this stage.
+ Vector128 maximumValue = Vector128.Create(this.MaximumValue);
+ Vector128 halfValue = Vector128.Create(this.HalfValue);
+ Vector128 scaleVector = Vector128.Create(scale);
+
+ for (; i <= oneVectorFromEnd; i += Vector128.Count)
+ {
+ ref Vector128 c0 = ref Unsafe.As>(ref Unsafe.Add(ref c0Base, i));
+ ref Vector128 c1 = ref Unsafe.As>(ref Unsafe.Add(ref c1Base, i));
+ ref Vector128 c2 = ref Unsafe.As>(ref Unsafe.Add(ref c2Base, i));
+
+ // As at the wider stages, the fourth vector is loaded only for CMYK-shaped operators.
+ Vector128 c3 = TOperator.ComponentCount == 4
+ ? Unsafe.As>(ref Unsafe.Add(ref c3Base, i))
+ : default;
+
+ TOperator.ConvertToRgb(ref c0, ref c1, ref c2, c3, maximumValue, halfValue, scaleVector);
+ }
+ }
+ }
+
+ // Fewer than four samples remain after the SIMD cascade. Processing from the shared offset
+ // guarantees each sample is visited exactly once for arbitrary test lengths and JPEG block rows.
+ for (; i < length; i++)
+ {
+ float c3 = TOperator.ComponentCount == 4 ? Unsafe.Add(ref c3Base, i) : 0;
+
+ TOperator.ConvertToRgb(
+ ref Unsafe.Add(ref c0Base, i),
+ ref Unsafe.Add(ref c1Base, i),
+ ref Unsafe.Add(ref c2Base, i),
+ c3,
+ this.MaximumValue,
+ this.HalfValue,
+ scale);
+ }
+ }
+
+ ///
+ public override void ConvertToRgbInPlaceWithIcc(Configuration configuration, in ComponentValues values, IccProfile profile)
+ => TOperator.ConvertToRgbInPlaceWithIcc(configuration, profile, values, this.MaximumValue);
+
+ ///
+ public override void ConvertFromRgb(in ComponentValues values, Span rLane, Span gLane, Span bLane)
+ {
+ // The encoder supplies equally sized RGB planes and destination component planes. Byrefs preserve
+ // contiguous access and allow the same proven vector boundary to govern every participating lane.
+ // Component3 is empty for three-component formats and is only written by four-component operators.
+ ref float c0Base = ref MemoryMarshal.GetReference(values.Component0);
+ ref float c1Base = ref MemoryMarshal.GetReference(values.Component1);
+ ref float c2Base = ref MemoryMarshal.GetReference(values.Component2);
+ ref float c3Base = ref MemoryMarshal.GetReference(values.Component3);
+ ref float rBase = ref MemoryMarshal.GetReference(rLane);
+ ref float gBase = ref MemoryMarshal.GetReference(gLane);
+ ref float bBase = ref MemoryMarshal.GetReference(bLane);
+
+ int length = values.Component0.Length;
+ int i = 0;
+ float scale = 1F / this.MaximumValue;
+
+ // Each vector overload returns planar component vectors. Storing them here keeps the
+ // operator concerned only with color arithmetic and preserves contiguous lane access.
+ if (Vector512.IsHardwareAccelerated)
+ {
+ // The end offset proves all three 64-byte RGB reads and all component writes are in range.
+ // A short row yields a negative end and falls through to the next supported width.
+ int oneVectorFromEnd = length - Vector512.Count;
+
+ if (i <= oneVectorFromEnd)
+ {
+ // Operators receive width-matched precision state only when this width has work, keeping
+ // invariant broadcasts outside the loop without charging narrower or scalar rows for them.
+ Vector512 maximumValue = Vector512.Create(this.MaximumValue);
+ Vector512 halfValue = Vector512.Create(this.HalfValue);
+ Vector512 scaleVector = Vector512.Create(scale);
+
+ for (; i <= oneVectorFromEnd; i += Vector512.Count)
+ {
+ Vector512 r = Unsafe.As>(ref Unsafe.Add(ref rBase, i));
+ Vector512 g = Unsafe.As>(ref Unsafe.Add(ref gBase, i));
+ Vector512 b = Unsafe.As>(ref Unsafe.Add(ref bBase, i));
+
+ TOperator.ConvertFromRgb(
+ r,
+ g,
+ b,
+ maximumValue,
+ halfValue,
+ scaleVector,
+ out Vector512 c0,
+ out Vector512 c1,
+ out Vector512 c2,
+ out Vector512 c3);
+
+ // Outputs remain planar: each vector contains sixteen consecutive samples from one
+ // JPEG component. Static count checks prevent grayscale from touching absent planes
+ // while disappearing completely from three- and four-component specializations.
+ Unsafe.As>(ref Unsafe.Add(ref c0Base, i)) = c0;
+
+ if (TOperator.ComponentCount >= 2)
+ {
+ Unsafe.As>(ref Unsafe.Add(ref c1Base, i)) = c1;
+ }
+
+ if (TOperator.ComponentCount >= 3)
+ {
+ Unsafe.As>(ref Unsafe.Add(ref c2Base, i)) = c2;
+ }
+
+ if (TOperator.ComponentCount >= 4)
+ {
+ Unsafe.As>(ref Unsafe.Add(ref c3Base, i)) = c3;
+ }
+ }
+ }
+ }
+
+ if (Vector256.IsHardwareAccelerated)
+ {
+ // Continue from the AVX-512 offset so an eight-sample tail stays vectorized on AVX-512 CPUs.
+ int oneVectorFromEnd = length - Vector256.Count;
+
+ if (i <= oneVectorFromEnd)
+ {
+ // Materialize YMM state only for an eight-sample remainder or an AVX2-only loop.
+ Vector256 maximumValue = Vector256.Create(this.MaximumValue);
+ Vector256 halfValue = Vector256.Create(this.HalfValue);
+ Vector256 scaleVector = Vector256.Create(scale);
+
+ for (; i <= oneVectorFromEnd; i += Vector256.Count)
+ {
+ Vector256 r = Unsafe.As>(ref Unsafe.Add(ref rBase, i));
+ Vector256 g = Unsafe.As>(ref Unsafe.Add(ref gBase, i));
+ Vector256