diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs index 6429b0ea8..02a0c42bb 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs @@ -18,8 +18,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { } - public override void ConvertFromRgbInplace(in ComponentValues values) => throw new System.NotImplementedException(); - public override void ConvertToRgbInplace(in ComponentValues values) { ref Vector256 c0Base = @@ -48,6 +46,47 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters y = Avx.Multiply(y, k); } } + + public override void ConvertFromRgbInplace(in ComponentValues values) + { + ref Vector256 c0Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + ref Vector256 c1Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); + ref Vector256 c2Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); + ref Vector256 c3Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); + + // Used for the color conversion + var scale = Vector256.Create(this.MaximumValue); + var one = Vector256.Create(1f); + + nint n = values.Component0.Length / Vector256.Count; + for (nint i = 0; i < n; i++) + { + ref Vector256 c0 = ref Unsafe.Add(ref c0Base, i); + ref Vector256 c1 = ref Unsafe.Add(ref c1Base, i); + ref Vector256 c2 = ref Unsafe.Add(ref c2Base, i); + ref Vector256 c3 = ref Unsafe.Add(ref c3Base, i); + + Vector256 ctmp = Avx.Subtract(one, c0); + Vector256 mtmp = Avx.Subtract(one, c1); + Vector256 ytmp = Avx.Subtract(one, c2); + Vector256 ktmp = Avx.Min(ctmp, Avx.Min(mtmp, ytmp)); + + Vector256 kMask = Avx.CompareNotEqual(ktmp, one); + + ctmp = Avx.And(Avx.Divide(Avx.Subtract(ctmp, ktmp), Avx.Subtract(one, ktmp)), kMask); + mtmp = Avx.And(Avx.Divide(Avx.Subtract(mtmp, ktmp), Avx.Subtract(one, ktmp)), kMask); + ytmp = Avx.And(Avx.Divide(Avx.Subtract(ytmp, ktmp), Avx.Subtract(one, ktmp)), kMask); + + c0 = Avx.Subtract(scale, Avx.Multiply(ctmp, scale)); + c1 = Avx.Subtract(scale, Avx.Multiply(mtmp, scale)); + c2 = Avx.Subtract(scale, Avx.Multiply(ytmp, scale)); + c3 = Avx.Subtract(scale, Avx.Multiply(ktmp, scale)); + } + } } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs index 17459a585..e951b5721 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs @@ -15,9 +15,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } public override void ConvertToRgbInplace(in ComponentValues values) => - ConvertCoreInplace(values, this.MaximumValue); + ConvertToRgbInplace(values, this.MaximumValue); - internal static void ConvertCoreInplace(in ComponentValues values, float maxValue) + public override void ConvertFromRgbInplace(in ComponentValues values) + => ConvertFromRgbInplace(values, this.MaximumValue); + + public static void ConvertToRgbInplace(in ComponentValues values, float maxValue) { Span c0 = values.Component0; Span c1 = values.Component1; @@ -39,7 +42,39 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } } - public override void ConvertFromRgbInplace(in ComponentValues values) => throw new NotImplementedException(); + public static void ConvertFromRgbInplace(in ComponentValues values, float maxValue) + { + Span c0 = values.Component0; + Span c1 = values.Component1; + Span c2 = values.Component2; + Span c3 = values.Component3; + + for (int i = 0; i < c0.Length; i++) + { + float ctmp = 1f - c0[i]; + float mtmp = 1f - c1[i]; + float ytmp = 1f - c2[i]; + float ktmp = MathF.Min(MathF.Min(ctmp, mtmp), ytmp); + + if (1f - ktmp <= float.Epsilon) + { + ctmp = 0f; + mtmp = 0f; + ytmp = 0f; + } + else + { + ctmp = (ctmp - ktmp) / (1f - ktmp); + mtmp = (mtmp - ktmp) / (1f - ktmp); + ytmp = (ytmp - ktmp) / (1f - ktmp); + } + + c0[i] = maxValue - (ctmp * maxValue); + c1[i] = maxValue - (mtmp * maxValue); + c2[i] = maxValue - (ytmp * maxValue); + c3[i] = maxValue - (ktmp * maxValue); + } + } } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs index 00ec1f868..d6c23f0e0 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs @@ -44,12 +44,51 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } } - protected override void ConvertCoreInplaceToRgb(in ComponentValues values) => - FromCmykScalar.ConvertCoreInplace(values, this.MaximumValue); + protected override void ConvertCoreInplaceToRgb(in ComponentValues values) + => FromCmykScalar.ConvertToRgbInplace(values, this.MaximumValue); - protected override void ConvertCoreVectorizedInplaceFromRgb(in ComponentValues values) => throw new System.NotImplementedException(); + protected override void ConvertCoreVectorizedInplaceFromRgb(in ComponentValues values) + { + ref Vector c0Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0)); + ref Vector c1Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1)); + ref Vector c2Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2)); + ref Vector c3Base = + ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3)); + + // Used for the color conversion + var scale = new Vector(this.MaximumValue); + var one = new Vector(1f); + + nint n = values.Component0.Length / Vector.Count; + for (nint i = 0; i < n; i++) + { + ref Vector c0 = ref Unsafe.Add(ref c0Base, i); + ref Vector c1 = ref Unsafe.Add(ref c1Base, i); + ref Vector c2 = ref Unsafe.Add(ref c2Base, i); + ref Vector c3 = ref Unsafe.Add(ref c3Base, i); + + Vector ctmp = one - c0; + Vector mtmp = one - c1; + Vector ytmp = one - c2; + Vector ktmp = Vector.Min(ctmp, Vector.Min(mtmp, ytmp)); + + var kMask = Vector.Equals(ktmp, Vector.One); + ctmp = Vector.AndNot((ctmp - ktmp) / (one - ktmp), kMask.As()); + mtmp = Vector.AndNot((mtmp - ktmp) / (one - ktmp), kMask.As()); + ytmp = Vector.AndNot((ytmp - ktmp) / (one - ktmp), kMask.As()); + + c0 = scale - (ctmp * scale); + c1 = scale - (mtmp * scale); + c2 = scale - (ytmp * scale); + c3 = scale - (ktmp * scale); + } + } - protected override void ConvertCoreInplaceFromRgb(in ComponentValues values) => throw new System.NotImplementedException(); + protected override void ConvertCoreInplaceFromRgb(in ComponentValues values) + => FromCmykScalar.ConvertFromRgbInplace(values, this.MaximumValue); } } }