diff --git a/src/ImageSharp/Common/Tuples/Tuple8.cs b/src/ImageSharp/Common/Tuples/Tuple8.cs
index 590a3f5c9..3335e6e37 100644
--- a/src/ImageSharp/Common/Tuples/Tuple8.cs
+++ b/src/ImageSharp/Common/Tuples/Tuple8.cs
@@ -4,7 +4,7 @@ namespace SixLabors.ImageSharp.Common.Tuples
{
///
/// Contains value type tuples of 8 elements.
- /// TODO: Should T4 this stuff to be DRY
+ /// TODO: We should T4 this stuff to be DRY
///
internal static class Tuple8
{
@@ -79,6 +79,9 @@ namespace SixLabors.ImageSharp.Common.Tuples
return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]";
}
+ ///
+ /// Sets the values of this tuple by casting all elements of the given tuple to .
+ ///
public void LoadFrom(ref OfUInt32 i)
{
this.V0 = (byte)i.V0;
diff --git a/src/ImageSharp/Common/Tuples/Vector4Pair.cs b/src/ImageSharp/Common/Tuples/Vector4Pair.cs
index 1be936b30..4f43c9811 100644
--- a/src/ImageSharp/Common/Tuples/Vector4Pair.cs
+++ b/src/ImageSharp/Common/Tuples/Vector4Pair.cs
@@ -39,10 +39,11 @@ namespace SixLabors.ImageSharp.Common.Tuples
}
///
- /// Color-conversion specific downscale method.
+ /// Downscale method, specific to Jpeg color conversion. Works only if Vector{float}.Count == 4!
+ /// TODO: Move it somewhere else.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal void RoundAndDownscaleBasic()
+ internal void RoundAndDownscalePreAvx2()
{
ref Vector a = ref Unsafe.As>(ref this.A);
a = a.FastRound();
@@ -56,7 +57,8 @@ namespace SixLabors.ImageSharp.Common.Tuples
}
///
- /// AVX2-only color-conversion specific downscale method.
+ /// AVX2-only Downscale method, specific to Jpeg color conversion.
+ /// TODO: Move it somewhere else.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void RoundAndDownscaleAvx2()
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.cs b/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.cs
index 4c1b4f4d1..e8614205c 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.cs
+++ b/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.cs
@@ -96,51 +96,56 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
///
/// Level shift by +128, clip to [0, 255]
///
- /// The destination block
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal void NormalizeColorsInto(ref Block8x8F d)
+ internal void NormalizeColorsInplace()
{
- d.V0L = Vector4.Clamp(V0L + COff4, CMin4, CMax4);
- d.V0R = Vector4.Clamp(V0R + COff4, CMin4, CMax4);
- d.V1L = Vector4.Clamp(V1L + COff4, CMin4, CMax4);
- d.V1R = Vector4.Clamp(V1R + COff4, CMin4, CMax4);
- d.V2L = Vector4.Clamp(V2L + COff4, CMin4, CMax4);
- d.V2R = Vector4.Clamp(V2R + COff4, CMin4, CMax4);
- d.V3L = Vector4.Clamp(V3L + COff4, CMin4, CMax4);
- d.V3R = Vector4.Clamp(V3R + COff4, CMin4, CMax4);
- d.V4L = Vector4.Clamp(V4L + COff4, CMin4, CMax4);
- d.V4R = Vector4.Clamp(V4R + COff4, CMin4, CMax4);
- d.V5L = Vector4.Clamp(V5L + COff4, CMin4, CMax4);
- d.V5R = Vector4.Clamp(V5R + COff4, CMin4, CMax4);
- d.V6L = Vector4.Clamp(V6L + COff4, CMin4, CMax4);
- d.V6R = Vector4.Clamp(V6R + COff4, CMin4, CMax4);
- d.V7L = Vector4.Clamp(V7L + COff4, CMin4, CMax4);
- d.V7R = Vector4.Clamp(V7R + COff4, CMin4, CMax4);
+ this.V0L = Vector4.Clamp(this.V0L + COff4, CMin4, CMax4);
+ this.V0R = Vector4.Clamp(this.V0R + COff4, CMin4, CMax4);
+ this.V1L = Vector4.Clamp(this.V1L + COff4, CMin4, CMax4);
+ this.V1R = Vector4.Clamp(this.V1R + COff4, CMin4, CMax4);
+ this.V2L = Vector4.Clamp(this.V2L + COff4, CMin4, CMax4);
+ this.V2R = Vector4.Clamp(this.V2R + COff4, CMin4, CMax4);
+ this.V3L = Vector4.Clamp(this.V3L + COff4, CMin4, CMax4);
+ this.V3R = Vector4.Clamp(this.V3R + COff4, CMin4, CMax4);
+ this.V4L = Vector4.Clamp(this.V4L + COff4, CMin4, CMax4);
+ this.V4R = Vector4.Clamp(this.V4R + COff4, CMin4, CMax4);
+ this.V5L = Vector4.Clamp(this.V5L + COff4, CMin4, CMax4);
+ this.V5R = Vector4.Clamp(this.V5R + COff4, CMin4, CMax4);
+ this.V6L = Vector4.Clamp(this.V6L + COff4, CMin4, CMax4);
+ this.V6R = Vector4.Clamp(this.V6R + COff4, CMin4, CMax4);
+ this.V7L = Vector4.Clamp(this.V7L + COff4, CMin4, CMax4);
+ this.V7R = Vector4.Clamp(this.V7R + COff4, CMin4, CMax4);
}
-
- ///
- /// Level shift by +128, clip to [0, 255]
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal void NormalizeColorsInplace()
+ public void NormalizeColorsAndRoundInplaceAvx2()
{
- this.V0L = Vector4.Clamp(V0L + COff4, CMin4, CMax4);
- this.V0R = Vector4.Clamp(V0R + COff4, CMin4, CMax4);
- this.V1L = Vector4.Clamp(V1L + COff4, CMin4, CMax4);
- this.V1R = Vector4.Clamp(V1R + COff4, CMin4, CMax4);
- this.V2L = Vector4.Clamp(V2L + COff4, CMin4, CMax4);
- this.V2R = Vector4.Clamp(V2R + COff4, CMin4, CMax4);
- this.V3L = Vector4.Clamp(V3L + COff4, CMin4, CMax4);
- this.V3R = Vector4.Clamp(V3R + COff4, CMin4, CMax4);
- this.V4L = Vector4.Clamp(V4L + COff4, CMin4, CMax4);
- this.V4R = Vector4.Clamp(V4R + COff4, CMin4, CMax4);
- this.V5L = Vector4.Clamp(V5L + COff4, CMin4, CMax4);
- this.V5R = Vector4.Clamp(V5R + COff4, CMin4, CMax4);
- this.V6L = Vector4.Clamp(V6L + COff4, CMin4, CMax4);
- this.V6R = Vector4.Clamp(V6R + COff4, CMin4, CMax4);
- this.V7L = Vector4.Clamp(V7L + COff4, CMin4, CMax4);
- this.V7R = Vector4.Clamp(V7R + COff4, CMin4, CMax4);
- }
- }
+ Vector off = new Vector(128f);
+ Vector max = new Vector(255F);
+
+
+ ref Vector row0 = ref Unsafe.As>(ref this.V0L);
+ row0 = NormalizeAndRound(row0, off, max);
+
+ ref Vector row1 = ref Unsafe.As>(ref this.V1L);
+ row1 = NormalizeAndRound(row1, off, max);
+
+ ref Vector row2 = ref Unsafe.As>(ref this.V2L);
+ row2 = NormalizeAndRound(row2, off, max);
+
+ ref Vector row3 = ref Unsafe.As>(ref this.V3L);
+ row3 = NormalizeAndRound(row3, off, max);
+
+ ref Vector row4 = ref Unsafe.As>(ref this.V4L);
+ row4 = NormalizeAndRound(row4, off, max);
+
+ ref Vector row5 = ref Unsafe.As>(ref this.V5L);
+ row5 = NormalizeAndRound(row5, off, max);
+
+ ref Vector row6 = ref Unsafe.As>(ref this.V6L);
+ row6 = NormalizeAndRound(row6, off, max);
+
+ ref Vector row7 = ref Unsafe.As>(ref this.V7L);
+ row7 = NormalizeAndRound(row7, off, max);
+ }
+ }
}
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.tt b/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.tt
index bef3e4914..9ab3ee12c 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.tt
+++ b/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.Generated.tt
@@ -61,9 +61,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
///
/// Level shift by +128, clip to [0, 255]
///
- /// The destination block
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal void TransformByteConvetibleColorValuesInto(ref Block8x8F d)
+ internal void NormalizeColorsInplace()
{
<#
@@ -74,11 +73,29 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
for (int j = 0; j < 2; j++)
{
char side = j == 0 ? 'L' : 'R';
- Write($"d.V{i}{side} = Vector4.Clamp(V{i}{side} + COff4, CMin4, CMax4);\r\n");
+ Write($"this.V{i}{side} = Vector4.Clamp(this.V{i}{side} + COff4, CMin4, CMax4);\r\n");
}
}
PopIndent();
#>
}
+
+ public void NormalizeColorsAndRoundInplaceAvx2()
+ {
+ Vector off = new Vector(128f);
+ Vector max = new Vector(255F);
+
+ <#
+
+ for (int i = 0; i < 8; i++)
+ {
+ #>
+
+ ref Vector row<#=i#> = ref Unsafe.As>(ref this.V<#=i#>L);
+ row<#=i#> = NormalizeAndRound(row<#=i#>, off, max);
+ <#
+ }
+ #>
+ }
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs
index 6ba69bec4..ff9db6ab9 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs
+++ b/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs
@@ -315,28 +315,31 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
///
/// Multiply all elements of the block.
///
- /// Vector to multiply by
+ /// The value to multiply by
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void MultiplyInplace(float scaleVec)
- {
- this.V0L *= scaleVec;
- this.V0R *= scaleVec;
- this.V1L *= scaleVec;
- this.V1R *= scaleVec;
- this.V2L *= scaleVec;
- this.V2R *= scaleVec;
- this.V3L *= scaleVec;
- this.V3R *= scaleVec;
- this.V4L *= scaleVec;
- this.V4R *= scaleVec;
- this.V5L *= scaleVec;
- this.V5R *= scaleVec;
- this.V6L *= scaleVec;
- this.V6R *= scaleVec;
- this.V7L *= scaleVec;
- this.V7R *= scaleVec;
+ public void MultiplyInplace(float value)
+ {
+ this.V0L *= value;
+ this.V0R *= value;
+ this.V1L *= value;
+ this.V1R *= value;
+ this.V2L *= value;
+ this.V2R *= value;
+ this.V3L *= value;
+ this.V3R *= value;
+ this.V4L *= value;
+ this.V4R *= value;
+ this.V5L *= value;
+ this.V5R *= value;
+ this.V6L *= value;
+ this.V6R *= value;
+ this.V7L *= value;
+ this.V7R *= value;
}
+ ///
+ /// Multiply all elements of the block by the corresponding elements of 'other'
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MultiplyInplace(ref Block8x8F other)
{
@@ -405,33 +408,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
}
}
- ///
- /// Level shift by +128, clip to [0, 255], and write to buffer.
- ///
- /// Color buffer
- /// Stride offset
- /// Temp Block pointer
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public unsafe void CopyColorsTo(Span destinationBuffer, int stride, Block8x8F* tempBlockPtr)
- {
- this.NormalizeColorsInto(ref *tempBlockPtr);
- ref byte d = ref destinationBuffer.DangerousGetPinnableReference();
- float* src = (float*)tempBlockPtr;
- for (int i = 0; i < 8; i++)
- {
- ref byte dRow = ref Unsafe.Add(ref d, i * stride);
- Unsafe.Add(ref dRow, 0) = (byte)src[0];
- Unsafe.Add(ref dRow, 1) = (byte)src[1];
- Unsafe.Add(ref dRow, 2) = (byte)src[2];
- Unsafe.Add(ref dRow, 3) = (byte)src[3];
- Unsafe.Add(ref dRow, 4) = (byte)src[4];
- Unsafe.Add(ref dRow, 5) = (byte)src[5];
- Unsafe.Add(ref dRow, 6) = (byte)src[6];
- Unsafe.Add(ref dRow, 7) = (byte)src[7];
- src += 8;
- }
- }
-
///
/// Unzig the elements of block into dest, while dividing them by elements of qt and "pre-rounding" the values.
/// To finish the rounding it's enough to (int)-cast these values.
@@ -529,29 +505,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
return result;
}
- public void NormalizeColorsAndRoundInplaceAvx2()
- {
- Vector off = new Vector(128f);
- Vector max = new Vector(255F);
-
- ref Vector row0 = ref Unsafe.As>(ref this.V0L);
- row0 = NormalizeAndRound(row0, off, max);
- ref Vector row1 = ref Unsafe.As>(ref this.V1L);
- row1 = NormalizeAndRound(row1, off, max);
- ref Vector row2 = ref Unsafe.As>(ref this.V2L);
- row2 = NormalizeAndRound(row2, off, max);
- ref Vector row3 = ref Unsafe.As>(ref this.V3L);
- row3 = NormalizeAndRound(row3, off, max);
- ref Vector row4 = ref Unsafe.As>(ref this.V4L);
- row4 = NormalizeAndRound(row4, off, max);
- ref Vector row5 = ref Unsafe.As>(ref this.V5L);
- row5 = NormalizeAndRound(row5, off, max);
- ref Vector row6 = ref Unsafe.As>(ref this.V6L);
- row6 = NormalizeAndRound(row6, off, max);
- ref Vector row7 = ref Unsafe.As>(ref this.V7L);
- row7 = NormalizeAndRound(row7, off, max);
- }
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector NormalizeAndRound(Vector row, Vector off, Vector max)
{
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegBlockPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegBlockPostProcessor.cs
index 0459a5df0..d0f2b8817 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegBlockPostProcessor.cs
+++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegBlockPostProcessor.cs
@@ -33,18 +33,32 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
///
public Block8x8F DequantiazationTable;
+ ///
+ /// Defines the horizontal and vertical scale we need to apply to the 8x8 sized block.
+ ///
private Size subSamplingDivisors;
///
- /// Initialize the instance on the stack.
+ /// Initializes a new instance of the struct.
///
- public static void Init(JpegBlockPostProcessor* postProcessor, IRawJpegData decoder, IJpegComponent component)
+ public JpegBlockPostProcessor(IRawJpegData decoder, IJpegComponent component)
{
int qtIndex = component.QuantizationTableIndex;
- postProcessor->DequantiazationTable = ZigZag.CreateDequantizationTable(ref decoder.QuantizationTables[qtIndex]);
- postProcessor->subSamplingDivisors = component.SubSamplingDivisors;
+ this.DequantiazationTable = ZigZag.CreateDequantizationTable(ref decoder.QuantizationTables[qtIndex]);
+ this.subSamplingDivisors = component.SubSamplingDivisors;
+
+ this.SourceBlock = default(Block8x8F);
+ this.WorkspaceBlock1 = default(Block8x8F);
+ this.WorkspaceBlock2 = default(Block8x8F);
}
+ ///
+ /// Processes 'sourceBlock' producing Jpeg color channel values from spectral values:
+ /// - Dequantize
+ /// - Applying IDCT
+ /// - Level shift by +128, clip to [0, 255]
+ /// - Copy the resultin color values into 'destArea' scaling up the block by amount defined in
+ ///
public void ProcessBlockColorsInto(
ref Block8x8 sourceBlock,
BufferArea destArea)
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegComponentPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegComponentPostProcessor.cs
index 53aafed01..87c1431e0 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegComponentPostProcessor.cs
+++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegComponentPostProcessor.cs
@@ -66,10 +66,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
///
/// Invoke for block rows, copy the result into .
///
- public unsafe void CopyBlocksToColorBuffer()
+ public void CopyBlocksToColorBuffer()
{
- var blockPp = default(JpegBlockPostProcessor);
- JpegBlockPostProcessor.Init(&blockPp, this.ImagePostProcessor.RawJpeg, this.Component);
+ var blockPp = new JpegBlockPostProcessor(this.ImagePostProcessor.RawJpeg, this.Component);
for (int y = 0; y < this.BlockRowsPerStep; y++)
{
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs
index 1398b2f89..8d1e585db 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs
@@ -222,33 +222,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
this.Output.WriteLine($"TranposeInto_PinningImpl_Benchmark finished in {sw.ElapsedMilliseconds} ms");
}
- [Fact]
- public unsafe void CopyColorsTo()
- {
- float[] data = Create8x8FloatData();
- var block = new Block8x8F();
- block.LoadFrom(data);
- block.MultiplyInplace(5);
-
- int stride = 256;
- int height = 42;
- int offset = height * 10 + 20;
-
- byte[] colorsExpected = new byte[stride * height];
- byte[] colorsActual = new byte[stride * height];
-
- var temp = new Block8x8F();
-
- ReferenceImplementations.CopyColorsTo(ref block, new Span(colorsExpected, offset), stride);
-
- block.CopyColorsTo(new Span(colorsActual, offset), stride, &temp);
-
- // Output.WriteLine("******* EXPECTED: *********");
- // PrintLinearData(colorsExpected);
- // Output.WriteLine("******** ACTUAL: **********");
- Assert.Equal(colorsExpected, colorsActual);
- }
-
private static float[] Create8x8ColorCropTestData()
{
float[] result = new float[64];
@@ -263,30 +236,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
return result;
}
- [Theory]
- [InlineData(false)]
- [InlineData(true)]
- public void NormalizeColors(bool inplace)
+ [Fact]
+ public void NormalizeColors()
{
var block = default(Block8x8F);
float[] input = Create8x8ColorCropTestData();
block.LoadFrom(input);
this.Output.WriteLine("Input:");
this.PrintLinearData(input);
-
- var dest = default(Block8x8F);
- if (inplace)
- {
- dest = block;
- dest.NormalizeColorsInplace();
- }
- else
- {
- block.NormalizeColorsInto(ref dest);
- }
+ Block8x8F dest = block;
+ dest.NormalizeColorsInplace();
-
float[] array = new float[64];
dest.CopyTo(array);
this.Output.WriteLine("Result:");