From 8e56cc41405aec0089988fcd33b740fe73848a4f Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 22 Aug 2017 23:17:01 +0200 Subject: [PATCH] ToString(), CopyTo(), ToArray() for Block8x8 --- .../Formats/Jpeg/Common/Block8x8.cs | 79 +++++++++++++------ .../Components/Decoder/JpegBlockProcessor.cs | 4 +- .../Components/Decoder/OldComponent.cs | 6 +- .../OldJpegScanDecoder.ComputationData.cs | 2 +- .../OldJpegScanDecoder.DataPointers.cs | 4 +- .../Components/Decoder/OldJpegScanDecoder.cs | 52 ++++++------ .../Jpeg/GolangPort/JpegEncoderCore.cs | 10 +-- .../Jpeg/GolangPort/OldJpegDecoderCore.cs | 20 ++--- .../General/RoundSinglePrecisionBlocks.cs | 14 ++-- .../Formats/Jpg/Block8x8Tests.cs | 13 ++- 10 files changed, 129 insertions(+), 75 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs b/src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs index a9ad4e9dd..c04ba1f83 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs @@ -1,10 +1,10 @@ using System; +using System.Diagnostics; using System.Runtime.CompilerServices; +using System.Text; namespace SixLabors.ImageSharp.Formats.Jpeg.Common { - using System.Diagnostics; - /// /// Represents a Jpeg block with coefficiens. /// @@ -25,6 +25,25 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common Unsafe.CopyBlock(ref selfRef, ref sourceRef, Size * sizeof(short)); } + public short this[int idx] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + GuardBlockIndex(idx); + ref short selfRef = ref Unsafe.As(ref this); + return Unsafe.Add(ref selfRef, idx); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + GuardBlockIndex(idx); + ref short selfRef = ref Unsafe.As(ref this); + Unsafe.Add(ref selfRef, idx) = value; + } + } + /// /// Pointer-based "Indexer" (getter part) /// @@ -32,11 +51,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common /// Index /// The scaleVec value at the specified index [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe short GetScalarAt(Block8x8* blockPtr, int idx) + public static short GetScalarAt(Block8x8* blockPtr, int idx) { GuardBlockIndex(idx); - short* fp = (short*)blockPtr; + short* fp = blockPtr->data; return fp[idx]; } @@ -47,32 +66,39 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common /// Index /// Value [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe void SetScalarAt(Block8x8* blockPtr, int idx, short value) + public static void SetScalarAt(Block8x8* blockPtr, int idx, short value) { GuardBlockIndex(idx); - short* fp = (short*)blockPtr; + short* fp = blockPtr->data; fp[idx] = value; } - public short this[int idx] + public Block8x8F AsFloatBlock() { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get + // TODO: Optimize this + var result = default(Block8x8F); + for (int i = 0; i < Size; i++) { - GuardBlockIndex(idx); - ref short selfRef = ref Unsafe.As(ref this); - return Unsafe.Add(ref selfRef, idx); + result[i] = this[i]; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - GuardBlockIndex(idx); - ref short selfRef = ref Unsafe.As(ref this); - Unsafe.Add(ref selfRef, idx) = value; - } + return result; + } + + public short[] ToArray() + { + short[] result = new short[Size]; + this.CopyTo(result); + return result; + } + + public void CopyTo(Span destination) + { + ref byte selfRef = ref Unsafe.As(ref this); + ref byte destRef = ref destination.NonPortableCast().DangerousGetPinnableReference(); + Unsafe.CopyBlock(ref destRef, ref selfRef, Size * sizeof(short)); } [Conditional("DEBUG")] @@ -82,16 +108,21 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common DebugGuard.MustBeGreaterThanOrEqualTo(idx, 0, nameof(idx)); } - public Block8x8F AsFloatBlock() + public override string ToString() { - // TODO: Optimize this - var result = default(Block8x8F); + var bld = new StringBuilder(); + bld.Append('['); for (int i = 0; i < Size; i++) { - result[i] = this[i]; + bld.Append(this[i]); + if (i < Size - 1) + { + bld.Append(','); + } } - return result; + bld.Append(']'); + return bld.ToString(); } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/JpegBlockProcessor.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/JpegBlockProcessor.cs index de28b3a7d..e58e7997d 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/JpegBlockProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/JpegBlockProcessor.cs @@ -67,7 +67,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder /// The y index of the block in private void ProcessBlockColors(OldJpegDecoderCore decoder, OldComponent component, int bx, int by) { - this.data.Block = component.GetBlockReference(bx, by); + ref Block8x8 sourceBlock = ref component.GetBlockReference(bx, by); + + this.data.Block = sourceBlock.AsFloatBlock(); int qtIndex = decoder.Components[this.componentIndex].Selector; this.data.QuantiazationTable = decoder.QuantizationTables[qtIndex]; diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldComponent.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldComponent.cs index 7b44c012d..90f4c60ee 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldComponent.cs +++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldComponent.cs @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder /// This is done by . /// When us true, we are touching these blocks multiple times - each time we process a Scan. /// - public Buffer2D SpectralBlocks { get; private set; } + public Buffer2D SpectralBlocks { get; private set; } /// /// Gets the number of blocks for this component along the X axis @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder /// public int BlockCountY { get; private set; } - public ref Block8x8F GetBlockReference(int bx, int by) + public ref Block8x8 GetBlockReference(int bx, int by) { return ref this.SpectralBlocks[bx, by]; } @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder { this.BlockCountX = decoder.MCUCountX * this.HorizontalFactor; this.BlockCountY = decoder.MCUCountY * this.VerticalFactor; - this.SpectralBlocks = Buffer2D.CreateClean(this.BlockCountX, this.BlockCountY); + this.SpectralBlocks = Buffer2D.CreateClean(this.BlockCountX, this.BlockCountY); } /// diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.ComputationData.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.ComputationData.cs index 8f999bbef..3aab69643 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.ComputationData.cs +++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.ComputationData.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder /// /// The main input/working block /// - public Block8x8F Block; + public Block8x8 Block; /// /// The jpeg unzig data diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.DataPointers.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.DataPointers.cs index 485884ca3..478c6470c 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.DataPointers.cs +++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.DataPointers.cs @@ -5,6 +5,8 @@ using Block8x8F = SixLabors.ImageSharp.Formats.Jpeg.Common.Block8x8F; namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder { + using SixLabors.ImageSharp.Formats.Jpeg.Common; + /// /// Conains the definition of /// @@ -18,7 +20,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder /// /// Pointer to /// - public Block8x8F* Block; + public Block8x8* Block; /// /// Pointer to as int* diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.cs index 2f0bf7715..f9798fb7d 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.cs @@ -9,6 +9,8 @@ using Block8x8F = SixLabors.ImageSharp.Formats.Jpeg.Common.Block8x8F; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder { + using SixLabors.ImageSharp.Formats.Jpeg.Common; + /// /// Encapsulates the impementation of Jpeg SOS Huffman decoding. See JpegScanDecoder.md! /// @@ -171,7 +173,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder // Find the block at (bx,by) in the component's buffer: OldComponent component = decoder.Components[this.ComponentIndex]; - ref Block8x8F blockRefOnHeap = ref component.GetBlockReference(this.bx, this.by); + ref Block8x8 blockRefOnHeap = ref component.GetBlockReference(this.bx, this.by); // Copy block to stack this.data.Block = blockRefOnHeap; @@ -273,7 +275,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder throw new ImageFormatException("Total sampling factors too large."); } - this.zigEnd = Block8x8F.ScalarCount - 1; + this.zigEnd = Block8x8F.Size - 1; if (decoder.IsProgressive) { @@ -283,7 +285,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder this.al = decoder.Temp[3 + scanComponentCountX2] & 0x0f; if ((this.zigStart == 0 && this.zigEnd != 0) || this.zigStart > this.zigEnd - || this.zigEnd >= Block8x8F.ScalarCount) + || this.zigEnd >= Block8x8F.Size) { throw new ImageFormatException("Bad spectral selection bounds"); } @@ -307,7 +309,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder /// The index of the scan private void DecodeBlock(OldJpegDecoderCore decoder, int scanIndex) { - Block8x8F* b = this.pointers.Block; + Block8x8* b = this.pointers.Block; int huffmannIdx = (OldHuffmanTree.AcTableIndex * OldHuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].AcTableSelector; if (this.ah != 0) { @@ -347,7 +349,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder this.pointers.Dc[this.ComponentIndex] += deltaDC; // b[0] = dc[compIndex] << al; - Block8x8F.SetScalarAt(b, 0, this.pointers.Dc[this.ComponentIndex] << this.al); + value = this.pointers.Dc[this.ComponentIndex] << this.al; + Block8x8.SetScalarAt(b, 0, (short) value); } if (zig <= this.zigEnd && this.eobRun > 0) @@ -384,7 +387,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder } // b[Unzig[zig]] = ac << al; - Block8x8F.SetScalarAt(b, this.pointers.Unzig[zig], ac << this.al); + value = ac << this.al; + Block8x8.SetScalarAt(b, this.pointers.Unzig[zig], (short)value); } else { @@ -501,7 +505,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder /// The low transform offset private void Refine(ref InputProcessor bp, ref OldHuffmanTree h, int delta) { - Block8x8F* b = this.pointers.Block; + Block8x8* b = this.pointers.Block; // Refining a DC component is trivial. if (this.zigStart == 0) @@ -520,13 +524,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder if (bit) { - int stuff = (int)Block8x8F.GetScalarAt(b, 0); + int stuff = (int)Block8x8.GetScalarAt(b, 0); // int stuff = (int)b[0]; stuff |= delta; // b[0] = stuff; - Block8x8F.SetScalarAt(b, 0, stuff); + Block8x8.SetScalarAt(b, 0, (short)stuff); } return; @@ -609,7 +613,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder if (z != 0) { // b[Unzig[zig]] = z; - Block8x8F.SetScalarAt(b, this.pointers.Unzig[zig], z); + Block8x8.SetScalarAt(b, this.pointers.Unzig[zig], (short)z); } } } @@ -632,11 +636,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder /// The private int RefineNonZeroes(ref InputProcessor bp, int zig, int nz, int delta) { - Block8x8F* b = this.pointers.Block; + Block8x8* b = this.pointers.Block; for (; zig <= this.zigEnd; zig++) { int u = this.pointers.Unzig[zig]; - float bu = Block8x8F.GetScalarAt(b, u); + int bu = Block8x8.GetScalarAt(b, u); // TODO: Are the equality comparsions OK with floating point values? Isn't an epsilon value necessary? if (bu == 0) @@ -662,16 +666,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder continue; } - if (bu >= 0) - { - // b[u] += delta; - Block8x8F.SetScalarAt(b, u, bu + delta); - } - else - { - // b[u] -= delta; - Block8x8F.SetScalarAt(b, u, bu - delta); - } + int val = bu >= 0 ? bu + delta : bu - delta; + + Block8x8.SetScalarAt(b, u, (short)val); + + //if (bu >= 0) + //{ + // // b[u] += delta; + // Block8x8.SetScalarAt(b, u, bu + delta); + //} + //else + //{ + // // b[u] -= delta; + // Block8x8.SetScalarAt(b, u, bu - delta); + //} } return zig; diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/JpegEncoderCore.cs index 229b8b7b5..9924e0b6e 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/GolangPort/JpegEncoderCore.cs @@ -262,7 +262,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort private static void WriteDataToDqt(byte[] dqt, ref int offset, QuantIndex i, ref Block8x8F quant) { dqt[offset++] = (byte)i; - for (int j = 0; j < Block8x8F.ScalarCount; j++) + for (int j = 0; j < Block8x8F.Size; j++) { dqt[offset++] = (byte)quant[j]; } @@ -276,7 +276,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort /// The quantization table. private static void InitQuantizationTable(int i, int scale, ref Block8x8F quant) { - for (int j = 0; j < Block8x8F.ScalarCount; j++) + for (int j = 0; j < Block8x8F.Size; j++) { int x = UnscaledQuant[i, j]; x = ((x * scale) + 50) / 100; @@ -576,7 +576,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort HuffIndex h = (HuffIndex)((2 * (int)index) + 1); int runLength = 0; - for (int zig = 1; zig < Block8x8F.ScalarCount; zig++) + for (int zig = 1; zig < Block8x8F.Size; zig++) { int ac = (int)unziggedDestPtr[zig]; @@ -660,12 +660,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort private void WriteDefineQuantizationTables() { // Marker + quantization table lengths - int markerlen = 2 + (QuantizationTableCount * (1 + Block8x8F.ScalarCount)); + int markerlen = 2 + (QuantizationTableCount * (1 + Block8x8F.Size)); this.WriteMarkerHeader(OldJpegConstants.Markers.DQT, markerlen); // Loop through and collect the tables as one array. // This allows us to reduce the number of writes to the stream. - int dqtCount = (QuantizationTableCount * Block8x8F.ScalarCount) + QuantizationTableCount; + int dqtCount = (QuantizationTableCount * Block8x8F.Size) + QuantizationTableCount; byte[] dqt = ArrayPool.Shared.Rent(dqtCount); int offset = 0; diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/OldJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/OldJpegDecoderCore.cs index dbf1bfcfb..a028215ba 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/OldJpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/GolangPort/OldJpegDecoderCore.cs @@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort this.configuration = configuration ?? Configuration.Default; this.HuffmanTrees = OldHuffmanTree.CreateHuffmanTrees(); this.QuantizationTables = new Block8x8F[MaxTq + 1]; - this.Temp = new byte[2 * Block8x8F.ScalarCount]; + this.Temp = new byte[2 * Block8x8F.Size]; } /// @@ -252,7 +252,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort } /// - /// Read metadata from stream and read the blocks in the scans into . + /// Read metadata from stream and read the blocks in the scans into . /// /// The metadata /// The stream @@ -1113,32 +1113,32 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort switch (x >> 4) { case 0: - if (remaining < Block8x8F.ScalarCount) + if (remaining < Block8x8F.Size) { done = true; break; } - remaining -= Block8x8F.ScalarCount; - this.InputProcessor.ReadFull(this.Temp, 0, Block8x8F.ScalarCount); + remaining -= Block8x8F.Size; + this.InputProcessor.ReadFull(this.Temp, 0, Block8x8F.Size); - for (int i = 0; i < Block8x8F.ScalarCount; i++) + for (int i = 0; i < Block8x8F.Size; i++) { this.QuantizationTables[tq][i] = this.Temp[i]; } break; case 1: - if (remaining < 2 * Block8x8F.ScalarCount) + if (remaining < 2 * Block8x8F.Size) { done = true; break; } - remaining -= 2 * Block8x8F.ScalarCount; - this.InputProcessor.ReadFull(this.Temp, 0, 2 * Block8x8F.ScalarCount); + remaining -= 2 * Block8x8F.Size; + this.InputProcessor.ReadFull(this.Temp, 0, 2 * Block8x8F.Size); - for (int i = 0; i < Block8x8F.ScalarCount; i++) + for (int i = 0; i < Block8x8F.Size; i++) { this.QuantizationTables[tq][i] = (this.Temp[2 * i] << 8) | this.Temp[(2 * i) + 1]; } diff --git a/tests/ImageSharp.Benchmarks/General/RoundSinglePrecisionBlocks.cs b/tests/ImageSharp.Benchmarks/General/RoundSinglePrecisionBlocks.cs index 284e20859..044e973a9 100644 --- a/tests/ImageSharp.Benchmarks/General/RoundSinglePrecisionBlocks.cs +++ b/tests/ImageSharp.Benchmarks/General/RoundSinglePrecisionBlocks.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General [GlobalSetup] public void Setup() { - for (int i = 0; i < Block8x8F.ScalarCount; i++) + for (int i = 0; i < Block8x8F.Size; i++) { this.inputDividend[i] = i*44.8f; this.inputDivisior[i] = 100 - i; @@ -44,18 +44,18 @@ namespace SixLabors.ImageSharp.Benchmarks.General float* pDividend = (float*)&b1; float* pDivisor = (float*)&b2; - int* result = stackalloc int[Block8x8F.ScalarCount]; + int* result = stackalloc int[Block8x8F.Size]; for (int cnt = 0; cnt < ExecutionCount; cnt++) { sum = 0; - for (int i = 0; i < Block8x8F.ScalarCount; i++) + for (int i = 0; i < Block8x8F.Size; i++) { int a = (int) pDividend[i]; int b = (int) pDivisor; result[i] = RationalRound(a, b); } - for (int i = 0; i < Block8x8F.ScalarCount; i++) + for (int i = 0; i < Block8x8F.Size; i++) { sum += result[i]; } @@ -77,12 +77,12 @@ namespace SixLabors.ImageSharp.Benchmarks.General for (int cnt = 0; cnt < ExecutionCount; cnt++) { sum = 0; - for (int i = 0; i < Block8x8F.ScalarCount; i++) + for (int i = 0; i < Block8x8F.Size; i++) { double value = pDividend[i] / pDivisor[i]; pDividend[i] = (float) System.Math.Round(value); } - for (int i = 0; i < Block8x8F.ScalarCount; i++) + for (int i = 0; i < Block8x8F.Size; i++) { sum += (int) pDividend[i]; } @@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General { sum = 0; DivideRoundAll(ref bDividend, ref bDivisor); - for (int i = 0; i < Block8x8F.ScalarCount; i++) + for (int i = 0; i < Block8x8F.Size; i++) { sum += (int)pDividend[i]; } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs index 46b12b80f..fafe56ee7 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Tests for (int i = 0; i < Block8x8.Size; i++) { - Block8x8.SetScalarAt(&block, i, i); + Block8x8.SetScalarAt(&block, i, (short)i); } sum = 0; @@ -76,5 +76,16 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal((float)data[i], dest[i]); } } + + [Fact] + public void ToArray() + { + short[] data = Create8x8ShortData(); + var block = new Block8x8(data); + + short[] result = block.ToArray(); + + Assert.Equal(data, result); + } } } \ No newline at end of file