Browse Source

Fixed color conversion

pull/2120/head
Dmitry Pentin 4 years ago
parent
commit
399a10cd4f
  1. 37
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromCmykAvx.cs
  2. 32
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromCmykScalar.cs
  3. 41
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromCmykVector.cs
  4. 29
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs
  5. 19
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs
  6. 32
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs
  7. 6
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromRgbAvx.cs
  8. 13
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromRgbScalar.cs
  9. 11
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromRgbVector.cs
  10. 35
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs
  11. 26
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs
  12. 36
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromYCbCrVector.cs
  13. 5
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromYccKAvx.cs
  14. 2
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromYccKScalar.cs
  15. 5
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromYccKVector.cs
  16. 2
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs
  17. 34
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector.cs
  18. 9
      src/ImageSharp/Formats/Jpeg/Components/Encoder/JpegComponentPostProcessor.cs
  19. 28
      src/ImageSharp/Formats/Jpeg/Components/Encoder/SpectralConverter{TPixel}.cs

37
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromCmykAvx.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
#if SUPPORTS_RUNTIME_INTRINSICS
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
@ -47,31 +48,33 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
}
public override void ConvertFromRgbInplace(in ComponentValues values)
public override void ConvertFromRgbInplace(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
ref Vector256<float> c0Base =
ref Vector256<float> destC =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector256<float> c1Base =
ref Vector256<float> destM =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector256<float> c2Base =
ref Vector256<float> destY =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector256<float> c3Base =
ref Vector256<float> destK =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component3));
ref Vector256<float> srcR =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(rLane));
ref Vector256<float> srcG =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(gLane));
ref Vector256<float> srcB =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(bLane));
// Used for the color conversion
var scale = Vector256.Create(this.MaximumValue);
nint n = values.Component0.Length / Vector256<float>.Count;
for (nint i = 0; i < n; i++)
{
ref Vector256<float> c0 = ref Unsafe.Add(ref c0Base, i);
ref Vector256<float> c1 = ref Unsafe.Add(ref c1Base, i);
ref Vector256<float> c2 = ref Unsafe.Add(ref c2Base, i);
ref Vector256<float> c3 = ref Unsafe.Add(ref c3Base, i);
Vector256<float> ctmp = Avx.Subtract(scale, c0);
Vector256<float> mtmp = Avx.Subtract(scale, c1);
Vector256<float> ytmp = Avx.Subtract(scale, c2);
Vector256<float> ctmp = Avx.Subtract(scale, Unsafe.Add(ref srcR, i));
Vector256<float> mtmp = Avx.Subtract(scale, Unsafe.Add(ref srcG, i));
Vector256<float> ytmp = Avx.Subtract(scale, Unsafe.Add(ref srcB, i));
Vector256<float> ktmp = Avx.Min(ctmp, Avx.Min(mtmp, ytmp));
Vector256<float> kMask = Avx.CompareNotEqual(ktmp, scale);
@ -80,10 +83,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
mtmp = Avx.And(Avx.Divide(Avx.Subtract(mtmp, ktmp), Avx.Subtract(scale, ktmp)), kMask);
ytmp = Avx.And(Avx.Divide(Avx.Subtract(ytmp, ktmp), Avx.Subtract(scale, 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, ktmp);
Unsafe.Add(ref destC, i) = Avx.Subtract(scale, Avx.Multiply(ctmp, scale));
Unsafe.Add(ref destM, i) = Avx.Subtract(scale, Avx.Multiply(mtmp, scale));
Unsafe.Add(ref destY, i) = Avx.Subtract(scale, Avx.Multiply(ytmp, scale));
Unsafe.Add(ref destK, i) = Avx.Subtract(scale, ktmp);
}
}
}

32
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromCmykScalar.cs

@ -17,8 +17,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
public override void ConvertToRgbInplace(in ComponentValues values) =>
ConvertToRgbInplace(values, this.MaximumValue);
public override void ConvertFromRgbInplace(in ComponentValues values)
=> ConvertFromRgbInplace(values, this.MaximumValue);
public override void ConvertFromRgbInplace(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> ConvertFromRgbInplace(values, this.MaximumValue, r, g, b);
public static void ConvertToRgbInplace(in ComponentValues values, float maxValue)
{
@ -42,21 +42,21 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
}
public static void ConvertFromRgbInplace(in ComponentValues values, float maxValue)
public static void ConvertFromRgbInplace(in ComponentValues values, float maxValue, Span<float> r, Span<float> g, Span<float> b)
{
Span<float> c0 = values.Component0;
Span<float> c1 = values.Component1;
Span<float> c2 = values.Component2;
Span<float> c3 = values.Component3;
Span<float> c = values.Component0;
Span<float> m = values.Component1;
Span<float> y = values.Component2;
Span<float> k = values.Component3;
for (int i = 0; i < c0.Length; i++)
for (int i = 0; i < c.Length; i++)
{
float ctmp = 255f - c0[i];
float mtmp = 255f - c1[i];
float ytmp = 255f - c2[i];
float ctmp = 255f - r[i];
float mtmp = 255f - g[i];
float ytmp = 255f - b[i];
float ktmp = MathF.Min(MathF.Min(ctmp, mtmp), ytmp);
if (255f - ktmp <= float.Epsilon)
if (ktmp >= 255f)
{
ctmp = 0f;
mtmp = 0f;
@ -69,10 +69,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
ytmp = (ytmp - ktmp) / (255f - ktmp);
}
c0[i] = maxValue - (ctmp * maxValue);
c1[i] = maxValue - (mtmp * maxValue);
c2[i] = maxValue - (ytmp * maxValue);
c3[i] = maxValue - ktmp;
c[i] = maxValue - (ctmp * maxValue);
m[i] = maxValue - (mtmp * maxValue);
y[i] = maxValue - (ytmp * maxValue);
k[i] = maxValue - ktmp;
}
}
}

41
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromCmykVector.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -47,31 +48,33 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
protected override void ConvertCoreInplaceToRgb(in ComponentValues values)
=> FromCmykScalar.ConvertToRgbInplace(values, this.MaximumValue);
protected override void ConvertCoreVectorizedInplaceFromRgb(in ComponentValues values)
protected override void ConvertCoreVectorizedInplaceFromRgb(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
{
ref Vector<float> c0Base =
ref Vector<float> destC =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector<float> c1Base =
ref Vector<float> destM =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector<float> c2Base =
ref Vector<float> destY =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector<float> c3Base =
ref Vector<float> destK =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component3));
ref Vector<float> srcR =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(r));
ref Vector<float> srcG =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(g));
ref Vector<float> srcB =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(b));
// Used for the color conversion
var scale = new Vector<float>(this.MaximumValue);
nint n = values.Component0.Length / Vector<float>.Count;
for (nint i = 0; i < n; i++)
{
ref Vector<float> c0 = ref Unsafe.Add(ref c0Base, i);
ref Vector<float> c1 = ref Unsafe.Add(ref c1Base, i);
ref Vector<float> c2 = ref Unsafe.Add(ref c2Base, i);
ref Vector<float> c3 = ref Unsafe.Add(ref c3Base, i);
Vector<float> ctmp = scale - c0;
Vector<float> mtmp = scale - c1;
Vector<float> ytmp = scale - c2;
Vector<float> ctmp = scale - Unsafe.Add(ref srcR, i);
Vector<float> mtmp = scale - Unsafe.Add(ref srcG, i);
Vector<float> ytmp = scale - Unsafe.Add(ref srcB, i);
Vector<float> ktmp = Vector.Min(ctmp, Vector.Min(mtmp, ytmp));
var kMask = Vector.Equals(ktmp, scale);
@ -79,15 +82,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
mtmp = Vector.AndNot((mtmp - ktmp) / (scale - ktmp), kMask.As<int, float>());
ytmp = Vector.AndNot((ytmp - ktmp) / (scale - ktmp), kMask.As<int, float>());
c0 = scale - (ctmp * scale);
c1 = scale - (mtmp * scale);
c2 = scale - (ytmp * scale);
c3 = scale - ktmp;
Unsafe.Add(ref destC, i) = scale - (ctmp * scale);
Unsafe.Add(ref destM, i) = scale - (mtmp * scale);
Unsafe.Add(ref destY, i) = scale - (ytmp * scale);
Unsafe.Add(ref destK, i) = scale - ktmp;
}
}
protected override void ConvertCoreInplaceFromRgb(in ComponentValues values)
=> FromCmykScalar.ConvertFromRgbInplace(values, this.MaximumValue);
protected override void ConvertCoreInplaceFromRgb(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> FromCmykScalar.ConvertFromRgbInplace(values, this.MaximumValue, r, g, b);
}
}
}

29
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs

@ -2,10 +2,12 @@
// Licensed under the Apache License, Version 2.0.
#if SUPPORTS_RUNTIME_INTRINSICS
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
using static SixLabors.ImageSharp.SimdUtils;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
@ -22,8 +24,33 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
}
public override void ConvertFromRgbInplace(in ComponentValues values)
public override void ConvertFromRgbInplace(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
ref Vector256<float> destLuminance =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector256<float> srcRed =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(rLane));
ref Vector256<float> srcGreen =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(gLane));
ref Vector256<float> srcBlue =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(bLane));
// Used for the color conversion
var f0299 = Vector256.Create(0.299f);
var f0587 = Vector256.Create(0.587f);
var f0114 = Vector256.Create(0.114f);
nint n = values.Component0.Length / Vector256<float>.Count;
for (nint i = 0; i < n; i++)
{
ref Vector256<float> r = ref Unsafe.Add(ref srcRed, i);
ref Vector256<float> g = ref Unsafe.Add(ref srcGreen, i);
ref Vector256<float> b = ref Unsafe.Add(ref srcBlue, i);
// luminocity = (0.299 * r) + (0.587 * g) + (0.114 * b)
Unsafe.Add(ref destLuminance, i) = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(Avx.Multiply(f0114, b), f0587, g), f0299, r);
}
}
}
}

19
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs

@ -2,8 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
@ -19,15 +17,26 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
public override void ConvertToRgbInplace(in ComponentValues values)
=> ConvertCoreInplaceToRgb(values.Component0, this.MaximumValue);
public override void ConvertFromRgbInplace(in ComponentValues values)
=> ConvertCoreInplaceFromRgb(values.Component0, this.MaximumValue);
public override void ConvertFromRgbInplace(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> ConvertCoreInplaceFromRgb(values, r, g, b);
internal static void ConvertCoreInplaceToRgb(Span<float> values, float maxValue)
{
}
internal static void ConvertCoreInplaceFromRgb(Span<float> values, float maxValue)
internal static void ConvertCoreInplaceFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
Span<float> c0 = values.Component0;
for (int i = 0; i < c0.Length; i++)
{
float r = rLane[i];
float g = gLane[i];
float b = bLane[i];
// luminocity = (0.299 * r) + (0.587 * g) + (0.114 * b)
c0[i] = (0.299f * r) + (0.587f * g) + (0.114f * b);
}
}
}
}

32
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -34,13 +35,36 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
protected override void ConvertCoreInplaceToRgb(in ComponentValues values)
=> FromGrayscaleScalar.ConvertCoreInplaceToRgb(values.Component0, this.MaximumValue);
protected override void ConvertCoreVectorizedInplaceFromRgb(in ComponentValues values)
protected override void ConvertCoreVectorizedInplaceFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
}
ref Vector<float> destLuma =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component0));
protected override void ConvertCoreInplaceFromRgb(in ComponentValues values)
{
ref Vector<float> srcR =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(rLane));
ref Vector<float> srcG =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(gLane));
ref Vector<float> srcB =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(bLane));
var rMult = new Vector<float>(0.299f);
var gMult = new Vector<float>(0.587f);
var bMult = new Vector<float>(0.114f);
nint n = values.Component0.Length / Vector<float>.Count;
for (nint i = 0; i < n; i++)
{
Vector<float> r = Unsafe.Add(ref srcR, i);
Vector<float> g = Unsafe.Add(ref srcR, i);
Vector<float> b = Unsafe.Add(ref srcR, i);
// luminocity = (0.299 * r) + (0.587 * g) + (0.114 * b)
Unsafe.Add(ref destLuma, i) = (rMult * r) + (gMult * g) + (bMult * b);
}
}
protected override void ConvertCoreInplaceFromRgb(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> FromGrayscaleScalar.ConvertCoreInplaceFromRgb(values, r, g, b);
}
}
}

6
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromRgbAvx.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
#if SUPPORTS_RUNTIME_INTRINSICS
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
@ -41,8 +42,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
}
public override void ConvertFromRgbInplace(in ComponentValues values)
public override void ConvertFromRgbInplace(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
rLane.CopyTo(values.Component0);
gLane.CopyTo(values.Component1);
bLane.CopyTo(values.Component2);
}
}
}

13
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromRgbScalar.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
internal abstract partial class JpegColorConverterBase
@ -13,10 +15,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
public override void ConvertToRgbInplace(in ComponentValues values)
=> ConvertCoreInplaceFromRgb(values, this.MaximumValue);
=> ConvertCoreInplaceToRgb(values, this.MaximumValue);
public override void ConvertFromRgbInplace(in ComponentValues values)
=> ConvertCoreInplaceFromRgb(values, this.MaximumValue);
public override void ConvertFromRgbInplace(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> ConvertCoreInplaceFromRgb(values, r, g, b);
internal static void ConvertCoreInplaceToRgb(ComponentValues values, float maxValue)
{
@ -25,8 +27,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
FromGrayscaleScalar.ConvertCoreInplaceToRgb(values.Component2, maxValue);
}
internal static void ConvertCoreInplaceFromRgb(ComponentValues values, float maxValue)
internal static void ConvertCoreInplaceFromRgb(ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
{
r.CopyTo(values.Component0);
g.CopyTo(values.Component1);
b.CopyTo(values.Component2);
}
}
}

11
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromRgbVector.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -42,13 +43,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
protected override void ConvertCoreInplaceToRgb(in ComponentValues values)
=> FromRgbScalar.ConvertCoreInplaceToRgb(values, this.MaximumValue);
protected override void ConvertCoreVectorizedInplaceFromRgb(in ComponentValues values)
protected override void ConvertCoreVectorizedInplaceFromRgb(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
{
r.CopyTo(values.Component0);
g.CopyTo(values.Component1);
b.CopyTo(values.Component2);
}
protected override void ConvertCoreInplaceFromRgb(in ComponentValues values)
{
}
protected override void ConvertCoreInplaceFromRgb(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> FromRgbScalar.ConvertCoreInplaceFromRgb(values, r, g, b);
}
}
}

35
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
#if SUPPORTS_RUNTIME_INTRINSICS
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
@ -69,15 +70,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
}
public override void ConvertFromRgbInplace(in ComponentValues values)
public override void ConvertFromRgbInplace(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
ref Vector256<float> c0Base =
ref Vector256<float> destY =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector256<float> c1Base =
ref Vector256<float> destCb =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector256<float> c2Base =
ref Vector256<float> destCr =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector256<float> srcR =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(rLane));
ref Vector256<float> srcG =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(gLane));
ref Vector256<float> srcB =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(bLane));
// Used for the color conversion
var chromaOffset = Vector256.Create(this.HalfValue);
@ -93,16 +101,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
nint n = values.Component0.Length / Vector256<float>.Count;
for (nint i = 0; i < n; i++)
{
ref Vector256<float> c0 = ref Unsafe.Add(ref c0Base, i);
ref Vector256<float> c1 = ref Unsafe.Add(ref c1Base, i);
ref Vector256<float> c2 = ref Unsafe.Add(ref c2Base, i);
// Vector256<float> r = Avx.Multiply(c0, scale);
// Vector256<float> g = Avx.Multiply(c1, scale);
// Vector256<float> b = Avx.Multiply(c2, scale);
Vector256<float> r = c0;
Vector256<float> g = c1;
Vector256<float> b = c2;
Vector256<float> r = Unsafe.Add(ref srcR, i);
Vector256<float> g = Unsafe.Add(ref srcG, i);
Vector256<float> b = Unsafe.Add(ref srcB, i);
// y = 0 + (0.299 * r) + (0.587 * g) + (0.114 * b)
// cb = 128 - (0.168736 * r) - (0.331264 * g) + (0.5 * b)
@ -111,9 +112,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
Vector256<float> cb = Avx.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(Avx.Multiply(f05, b), fn0331264, g), fn0168736, r));
Vector256<float> cr = Avx.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(Avx.Multiply(fn0081312F, b), fn0418688, g), f05, r));
c0 = y;
c1 = cb;
c2 = cr;
Unsafe.Add(ref destY, i) = y;
Unsafe.Add(ref destCb, i) = cb;
Unsafe.Add(ref destCr, i) = cr;
}
}
}

26
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs

@ -23,8 +23,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
public override void ConvertToRgbInplace(in ComponentValues values)
=> ConvertCoreInplaceToRgb(values, this.MaximumValue, this.HalfValue);
public override void ConvertFromRgbInplace(in ComponentValues values)
=> ConvertCoreInplaceFromRgb(values, this.MaximumValue, this.HalfValue);
public override void ConvertFromRgbInplace(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> ConvertCoreInplaceFromRgb(values, this.HalfValue, r, g, b);
public static void ConvertCoreInplaceToRgb(in ComponentValues values, float maxValue, float halfValue)
{
@ -49,24 +49,24 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
}
public static void ConvertCoreInplaceFromRgb(in ComponentValues values, float maxValue, float halfValue)
public static void ConvertCoreInplaceFromRgb(in ComponentValues values, float halfValue, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
Span<float> c0 = values.Component0;
Span<float> c1 = values.Component1;
Span<float> c2 = values.Component2;
Span<float> y = values.Component0;
Span<float> cb = values.Component1;
Span<float> cr = values.Component2;
for (int i = 0; i < c0.Length; i++)
for (int i = 0; i < y.Length; i++)
{
float r = c0[i];
float g = c1[i];
float b = c2[i];
float r = rLane[i];
float g = gLane[i];
float b = bLane[i];
// y = 0 + (0.299 * r) + (0.587 * g) + (0.114 * b)
// cb = 128 - (0.168736 * r) - (0.331264 * g) + (0.5 * b)
// cr = 128 + (0.5 * r) - (0.418688 * g) - (0.081312 * b)
c0[i] = (0.299f * r) + (0.587f * g) + (0.114f * b);
c1[i] = halfValue - (0.168736f * r) - (0.331264f * g) + (0.5f * b);
c2[i] = halfValue + (0.5f * r) - (0.418688f * g) - (0.081312f * b);
y[i] = (0.299f * r) + (0.587f * g) + (0.114f * b);
cb[i] = halfValue - (0.168736f * r) - (0.331264f * g) + (0.5f * b);
cr[i] = halfValue + (0.5f * r) - (0.418688f * g) - (0.081312f * b);
}
}
}

36
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromYCbCrVector.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -70,15 +71,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
protected override void ConvertCoreInplaceToRgb(in ComponentValues values)
=> FromYCbCrScalar.ConvertCoreInplaceToRgb(values, this.MaximumValue, this.HalfValue);
protected override void ConvertCoreVectorizedInplaceFromRgb(in ComponentValues values)
protected override void ConvertCoreVectorizedInplaceFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
ref Vector<float> c0Base =
ref Vector<float> destY =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector<float> c1Base =
ref Vector<float> destCb =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector<float> c2Base =
ref Vector<float> destCr =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector<float> srcR =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(rLane));
ref Vector<float> srcG =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(gLane));
ref Vector<float> srcB =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(bLane));
var chromaOffset = new Vector<float>(this.HalfValue);
var rYMult = new Vector<float>(0.299f);
@ -96,25 +104,21 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
nint n = values.Component0.Length / Vector<float>.Count;
for (nint i = 0; i < n; i++)
{
ref Vector<float> c0 = ref Unsafe.Add(ref c0Base, i);
ref Vector<float> c1 = ref Unsafe.Add(ref c1Base, i);
ref Vector<float> c2 = ref Unsafe.Add(ref c2Base, i);
Vector<float> r = c0;
Vector<float> g = c1;
Vector<float> b = c2;
Vector<float> r = Unsafe.Add(ref srcR, i);
Vector<float> g = Unsafe.Add(ref srcG, i);
Vector<float> b = Unsafe.Add(ref srcB, i);
// y = 0 + (0.299 * r) + (0.587 * g) + (0.114 * b)
// cb = 128 - (0.168736 * r) - (0.331264 * g) + (0.5 * b)
// cr = 128 + (0.5 * r) - (0.418688 * g) - (0.081312 * b)
c0 = (rYMult * r) + (gYMult * g) + (bYMult * b);
c1 = chromaOffset - (rCbMult * r) - (gCbMult * g) + (bCbMult * b);
c2 = chromaOffset + (rCrMult * r) - (gCrMult * g) - (bCrMult * b);
Unsafe.Add(ref destY, i) = (rYMult * r) + (gYMult * g) + (bYMult * b);
Unsafe.Add(ref destCb, i) = chromaOffset - (rCbMult * r) - (gCbMult * g) + (bCbMult * b);
Unsafe.Add(ref destCr, i) = chromaOffset + (rCrMult * r) - (gCrMult * g) - (bCrMult * b);
}
}
protected override void ConvertCoreInplaceFromRgb(in ComponentValues values)
=> FromYCbCrScalar.ConvertCoreInplaceFromRgb(values, this.MaximumValue, this.HalfValue);
protected override void ConvertCoreInplaceFromRgb(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> FromYCbCrScalar.ConvertCoreInplaceFromRgb(values, this.HalfValue, r, g, b);
}
}
}

5
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromYccKAvx.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
#if SUPPORTS_RUNTIME_INTRINSICS
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
@ -77,8 +78,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
}
public override void ConvertFromRgbInplace(in ComponentValues values)
=> throw new System.NotImplementedException();
public override void ConvertFromRgbInplace(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> throw new NotImplementedException();
}
}
}

2
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromYccKScalar.cs

@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
}
public override void ConvertFromRgbInplace(in ComponentValues values)
public override void ConvertFromRgbInplace(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> throw new NotImplementedException();
}
}

5
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.FromYccKVector.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -71,10 +72,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
protected override void ConvertCoreInplaceToRgb(in ComponentValues values) =>
FromYccKScalar.ConvertToRgpInplace(values, this.MaximumValue, this.HalfValue);
protected override void ConvertCoreVectorizedInplaceFromRgb(in ComponentValues values)
protected override void ConvertCoreVectorizedInplaceFromRgb(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> throw new System.NotImplementedException();
protected override void ConvertCoreInplaceFromRgb(in ComponentValues values)
protected override void ConvertCoreInplaceFromRgb(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
=> throw new System.NotImplementedException();
}
}

2
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs

@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// <param name="values">The input/ouptut as a stack-only <see cref="ComponentValues"/> struct</param>
public abstract void ConvertToRgbInplace(in ComponentValues values);
public abstract void ConvertFromRgbInplace(in ComponentValues values);
public abstract void ConvertFromRgbInplace(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b);
/// <summary>
/// Returns the <see cref="JpegColorConverterBase"/>s for all supported colorspaces and precisions.

34
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterVector.cs

@ -35,13 +35,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
int length = values.Component0.Length;
int remainder = (int)((uint)length % (uint)Vector<float>.Count);
// Jpeg images are guaranteed to have pixel strides at least 8 pixels wide
// Thus there's no need to check whether simdCount is greater than zero
int simdCount = length - remainder;
this.ConvertCoreVectorizedInplaceToRgb(values.Slice(0, simdCount));
if (simdCount > 0)
{
this.ConvertCoreVectorizedInplaceToRgb(values.Slice(0, simdCount));
}
// Jpeg images width is always divisible by 8 without a remainder
// so it's safe to say SSE/AVX implementations would never have
// so it's safe to say SSE/AVX1/AVX2 implementations would never have
// 'remainder' pixels
// But some exotic simd implementations e.g. AVX-512 can have
// remainder pixels
@ -51,26 +52,35 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
}
public override void ConvertFromRgbInplace(in ComponentValues values)
public override void ConvertFromRgbInplace(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b)
{
DebugGuard.IsTrue(this.IsAvailable, $"{this.GetType().Name} converter is not supported on current hardware.");
int length = values.Component0.Length;
int remainder = (int)((uint)length % (uint)Vector<float>.Count);
// Jpeg images are guaranteed to have pixel strides at least 8 pixels wide
// Thus there's no need to check whether simdCount is greater than zero
int simdCount = length - remainder;
this.ConvertCoreVectorizedInplaceFromRgb(values.Slice(0, simdCount));
if (simdCount > 0)
{
this.ConvertCoreVectorizedInplaceFromRgb(
values.Slice(0, simdCount),
r.Slice(0, simdCount),
g.Slice(0, simdCount),
b.Slice(0, simdCount));
}
// Jpeg images width is always divisible by 8 without a remainder
// so it's safe to say SSE/AVX implementations would never have
// so it's safe to say SSE/AVX1/AVX2 implementations would never have
// 'remainder' pixels
// But some exotic simd implementations e.g. AVX-512 can have
// remainder pixels
if (remainder > 0)
{
this.ConvertCoreInplaceFromRgb(values.Slice(simdCount, remainder));
this.ConvertCoreInplaceFromRgb(
values.Slice(simdCount, remainder),
r.Slice(simdCount, remainder),
g.Slice(simdCount, remainder),
b.Slice(simdCount, remainder));
}
}
@ -78,9 +88,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
protected abstract void ConvertCoreInplaceToRgb(in ComponentValues values);
protected abstract void ConvertCoreVectorizedInplaceFromRgb(in ComponentValues values);
protected abstract void ConvertCoreVectorizedInplaceFromRgb(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b);
protected abstract void ConvertCoreInplaceFromRgb(in ComponentValues values);
protected abstract void ConvertCoreInplaceFromRgb(in ComponentValues values, Span<float> r, Span<float> g, Span<float> b);
}
}
}

9
src/ImageSharp/Formats/Jpeg/Components/Encoder/JpegComponentPostProcessor.cs

@ -60,14 +60,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
this.PackColorBuffer();
}
for (int y = 0; y < spectralBuffer.Height; y++)
int blocksRowsPerStep = this.component.SamplingFactors.Height;
for (int y = 0; y < blocksRowsPerStep; y++)
{
int yBuffer = y * this.blockAreaSize.Height;
Span<float> colorBufferRow = this.ColorBuffer.DangerousGetRowSpan(yBuffer);
Span<Block8x8> blockRow = spectralBuffer.DangerousGetRowSpan(yBlockStart + y);
for (int xBlock = 0; xBlock < spectralBuffer.Width; xBlock++)
{
Span<float> colorBufferRow = this.ColorBuffer.DangerousGetRowSpan(yBuffer);
Span<Block8x8> blockRow = spectralBuffer.DangerousGetRowSpan(yBlockStart + y);
// load 8x8 block from 8 pixel strides
int xColorBufferStart = xBlock * 8;
workspaceBlock.ScaledCopyFrom(

28
src/ImageSharp/Formats/Jpeg/Components/Encoder/SpectralConverter{TPixel}.cs

@ -23,6 +23,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
private Buffer2D<TPixel> pixelBuffer;
private IMemoryOwner<float> redLane;
private IMemoryOwner<float> greenLane;
private IMemoryOwner<float> blueLane;
private int alignedPixelWidth;
private JpegColorConverterBase colorConverter;
@ -55,6 +61,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
this.componentProcessors[i] = new JpegComponentPostProcessor(allocator, component, postProcessorBufferSize, dequantTables[component.QuantizationTableIndex]);
}
this.redLane = allocator.Allocate<float>(this.alignedPixelWidth);
this.greenLane = allocator.Allocate<float>(this.alignedPixelWidth);
this.blueLane = allocator.Allocate<float>(this.alignedPixelWidth);
// color converter from Rgb24 to YCbCr
this.colorConverter = JpegColorConverterBase.GetConverter(colorSpace: frame.ColorSpace, precision: 8);
}
@ -67,6 +77,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
this.ConvertStride(spectralStep: 0);
}
public void ConvertFull()
{
int steps = (int)Numerics.DivideCeil((uint)this.pixelBuffer.Height, (uint)this.pixelRowsPerStep);
for (int i = 0; i < steps; i++)
{
this.ConvertStride(i);
}
}
private void ConvertStride(int spectralStep)
{
// 1. Unpack from TPixel to r/g/b planes
@ -75,6 +94,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
// 4. Convert color buffer to spectral blocks with component post processors
int maxY = Math.Min(this.pixelBuffer.Height, this.pixelRowCounter + this.pixelRowsPerStep);
Span<float> rLane = this.redLane.GetSpan();
Span<float> gLane = this.greenLane.GetSpan();
Span<float> bLane = this.blueLane.GetSpan();
for (int yy = this.pixelRowCounter; yy < maxY; yy++)
{
int y = yy - this.pixelRowCounter;
@ -82,10 +104,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
// unpack TPixel to r/g/b planes
Span<TPixel> sourceRow = this.pixelBuffer.DangerousGetRowSpan(yy);
var values = new JpegColorConverterBase.ComponentValues(this.componentProcessors, y);
PixelOperations<TPixel>.Instance.UnpackIntoRgbPlanes(this.configuration, values.Component0, values.Component1, values.Component2, sourceRow);
PixelOperations<TPixel>.Instance.UnpackIntoRgbPlanes(this.configuration, rLane, gLane, bLane, sourceRow);
this.colorConverter.ConvertFromRgbInplace(values);
var values = new JpegColorConverterBase.ComponentValues(this.componentProcessors, y);
this.colorConverter.ConvertFromRgbInplace(values, rLane, gLane, bLane);
}
for (int i = 0; i < this.componentProcessors.Length; i++)

Loading…
Cancel
Save