Browse Source

ToString(), CopyTo(), ToArray() for Block8x8

af/merge-core
Anton Firszov 9 years ago
parent
commit
8e56cc4140
  1. 79
      src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs
  2. 4
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/JpegBlockProcessor.cs
  3. 6
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldComponent.cs
  4. 2
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.ComputationData.cs
  5. 4
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.DataPointers.cs
  6. 52
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.cs
  7. 10
      src/ImageSharp/Formats/Jpeg/GolangPort/JpegEncoderCore.cs
  8. 20
      src/ImageSharp/Formats/Jpeg/GolangPort/OldJpegDecoderCore.cs
  9. 14
      tests/ImageSharp.Benchmarks/General/RoundSinglePrecisionBlocks.cs
  10. 13
      tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs

79
src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs

@ -1,10 +1,10 @@
using System; using System;
using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text;
namespace SixLabors.ImageSharp.Formats.Jpeg.Common namespace SixLabors.ImageSharp.Formats.Jpeg.Common
{ {
using System.Diagnostics;
/// <summary> /// <summary>
/// Represents a Jpeg block with <see cref="short"/> coefficiens. /// Represents a Jpeg block with <see cref="short"/> coefficiens.
/// </summary> /// </summary>
@ -25,6 +25,25 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
Unsafe.CopyBlock(ref selfRef, ref sourceRef, Size * sizeof(short)); 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<Block8x8, short>(ref this);
return Unsafe.Add(ref selfRef, idx);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
GuardBlockIndex(idx);
ref short selfRef = ref Unsafe.As<Block8x8, short>(ref this);
Unsafe.Add(ref selfRef, idx) = value;
}
}
/// <summary> /// <summary>
/// Pointer-based "Indexer" (getter part) /// Pointer-based "Indexer" (getter part)
/// </summary> /// </summary>
@ -32,11 +51,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
/// <param name="idx">Index</param> /// <param name="idx">Index</param>
/// <returns>The scaleVec value at the specified index</returns> /// <returns>The scaleVec value at the specified index</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe short GetScalarAt(Block8x8* blockPtr, int idx) public static short GetScalarAt(Block8x8* blockPtr, int idx)
{ {
GuardBlockIndex(idx); GuardBlockIndex(idx);
short* fp = (short*)blockPtr; short* fp = blockPtr->data;
return fp[idx]; return fp[idx];
} }
@ -47,32 +66,39 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
/// <param name="idx">Index</param> /// <param name="idx">Index</param>
/// <param name="value">Value</param> /// <param name="value">Value</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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); GuardBlockIndex(idx);
short* fp = (short*)blockPtr; short* fp = blockPtr->data;
fp[idx] = value; fp[idx] = value;
} }
public short this[int idx] public Block8x8F AsFloatBlock()
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] // TODO: Optimize this
get var result = default(Block8x8F);
for (int i = 0; i < Size; i++)
{ {
GuardBlockIndex(idx); result[i] = this[i];
ref short selfRef = ref Unsafe.As<Block8x8, short>(ref this);
return Unsafe.Add(ref selfRef, idx);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] return result;
set }
{
GuardBlockIndex(idx); public short[] ToArray()
ref short selfRef = ref Unsafe.As<Block8x8, short>(ref this); {
Unsafe.Add(ref selfRef, idx) = value; short[] result = new short[Size];
} this.CopyTo(result);
return result;
}
public void CopyTo(Span<short> destination)
{
ref byte selfRef = ref Unsafe.As<Block8x8, byte>(ref this);
ref byte destRef = ref destination.NonPortableCast<short, byte>().DangerousGetPinnableReference();
Unsafe.CopyBlock(ref destRef, ref selfRef, Size * sizeof(short));
} }
[Conditional("DEBUG")] [Conditional("DEBUG")]
@ -82,16 +108,21 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
DebugGuard.MustBeGreaterThanOrEqualTo(idx, 0, nameof(idx)); DebugGuard.MustBeGreaterThanOrEqualTo(idx, 0, nameof(idx));
} }
public Block8x8F AsFloatBlock() public override string ToString()
{ {
// TODO: Optimize this var bld = new StringBuilder();
var result = default(Block8x8F); bld.Append('[');
for (int i = 0; i < Size; i++) 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();
} }
} }
} }

4
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/JpegBlockProcessor.cs

@ -67,7 +67,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <param name="by">The y index of the block in <see cref="OldComponent.SpectralBlocks"/></param> /// <param name="by">The y index of the block in <see cref="OldComponent.SpectralBlocks"/></param>
private void ProcessBlockColors(OldJpegDecoderCore decoder, OldComponent component, int bx, int by) 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; int qtIndex = decoder.Components[this.componentIndex].Selector;
this.data.QuantiazationTable = decoder.QuantizationTables[qtIndex]; this.data.QuantiazationTable = decoder.QuantizationTables[qtIndex];

6
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 <see cref="OldJpegDecoderCore.ProcessBlocksIntoJpegImageChannels{TPixel}"/>. /// This is done by <see cref="OldJpegDecoderCore.ProcessBlocksIntoJpegImageChannels{TPixel}"/>.
/// When <see cref="OldJpegDecoderCore.IsProgressive"/> us true, we are touching these blocks multiple times - each time we process a Scan. /// When <see cref="OldJpegDecoderCore.IsProgressive"/> us true, we are touching these blocks multiple times - each time we process a Scan.
/// </summary> /// </summary>
public Buffer2D<Block8x8F> SpectralBlocks { get; private set; } public Buffer2D<Block8x8> SpectralBlocks { get; private set; }
/// <summary> /// <summary>
/// Gets the number of blocks for this component along the X axis /// Gets the number of blocks for this component along the X axis
@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// </summary> /// </summary>
public int BlockCountY { get; private set; } 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]; 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.BlockCountX = decoder.MCUCountX * this.HorizontalFactor;
this.BlockCountY = decoder.MCUCountY * this.VerticalFactor; this.BlockCountY = decoder.MCUCountY * this.VerticalFactor;
this.SpectralBlocks = Buffer2D<Block8x8F>.CreateClean(this.BlockCountX, this.BlockCountY); this.SpectralBlocks = Buffer2D<Block8x8>.CreateClean(this.BlockCountX, this.BlockCountY);
} }
/// <summary> /// <summary>

2
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.ComputationData.cs

@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <summary> /// <summary>
/// The main input/working block /// The main input/working block
/// </summary> /// </summary>
public Block8x8F Block; public Block8x8 Block;
/// <summary> /// <summary>
/// The jpeg unzig data /// The jpeg unzig data

4
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 namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{ {
using SixLabors.ImageSharp.Formats.Jpeg.Common;
/// <content> /// <content>
/// Conains the definition of <see cref="DataPointers"/> /// Conains the definition of <see cref="DataPointers"/>
/// </content> /// </content>
@ -18,7 +20,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <summary> /// <summary>
/// Pointer to <see cref="ComputationData.Block"/> /// Pointer to <see cref="ComputationData.Block"/>
/// </summary> /// </summary>
public Block8x8F* Block; public Block8x8* Block;
/// <summary> /// <summary>
/// Pointer to <see cref="ComputationData.Unzig"/> as int* /// Pointer to <see cref="ComputationData.Unzig"/> as int*

52
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OldJpegScanDecoder.cs

@ -9,6 +9,8 @@ using Block8x8F = SixLabors.ImageSharp.Formats.Jpeg.Common.Block8x8F;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{ {
using SixLabors.ImageSharp.Formats.Jpeg.Common;
/// <summary> /// <summary>
/// Encapsulates the impementation of Jpeg SOS Huffman decoding. See JpegScanDecoder.md! /// 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: // Find the block at (bx,by) in the component's buffer:
OldComponent component = decoder.Components[this.ComponentIndex]; 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 // Copy block to stack
this.data.Block = blockRefOnHeap; this.data.Block = blockRefOnHeap;
@ -273,7 +275,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
throw new ImageFormatException("Total sampling factors too large."); throw new ImageFormatException("Total sampling factors too large.");
} }
this.zigEnd = Block8x8F.ScalarCount - 1; this.zigEnd = Block8x8F.Size - 1;
if (decoder.IsProgressive) if (decoder.IsProgressive)
{ {
@ -283,7 +285,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
this.al = decoder.Temp[3 + scanComponentCountX2] & 0x0f; this.al = decoder.Temp[3 + scanComponentCountX2] & 0x0f;
if ((this.zigStart == 0 && this.zigEnd != 0) || this.zigStart > this.zigEnd 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"); throw new ImageFormatException("Bad spectral selection bounds");
} }
@ -307,7 +309,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <param name="scanIndex">The index of the scan</param> /// <param name="scanIndex">The index of the scan</param>
private void DecodeBlock(OldJpegDecoderCore decoder, int scanIndex) 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; int huffmannIdx = (OldHuffmanTree.AcTableIndex * OldHuffmanTree.ThRowSize) + this.pointers.ComponentScan[scanIndex].AcTableSelector;
if (this.ah != 0) if (this.ah != 0)
{ {
@ -347,7 +349,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
this.pointers.Dc[this.ComponentIndex] += deltaDC; this.pointers.Dc[this.ComponentIndex] += deltaDC;
// b[0] = dc[compIndex] << al; // 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) if (zig <= this.zigEnd && this.eobRun > 0)
@ -384,7 +387,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
} }
// b[Unzig[zig]] = ac << al; // 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 else
{ {
@ -501,7 +505,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <param name="delta">The low transform offset</param> /// <param name="delta">The low transform offset</param>
private void Refine(ref InputProcessor bp, ref OldHuffmanTree h, int delta) 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. // Refining a DC component is trivial.
if (this.zigStart == 0) if (this.zigStart == 0)
@ -520,13 +524,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
if (bit) if (bit)
{ {
int stuff = (int)Block8x8F.GetScalarAt(b, 0); int stuff = (int)Block8x8.GetScalarAt(b, 0);
// int stuff = (int)b[0]; // int stuff = (int)b[0];
stuff |= delta; stuff |= delta;
// b[0] = stuff; // b[0] = stuff;
Block8x8F.SetScalarAt(b, 0, stuff); Block8x8.SetScalarAt(b, 0, (short)stuff);
} }
return; return;
@ -609,7 +613,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
if (z != 0) if (z != 0)
{ {
// b[Unzig[zig]] = z; // 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
/// <returns>The <see cref="int" /></returns> /// <returns>The <see cref="int" /></returns>
private int RefineNonZeroes(ref InputProcessor bp, int zig, int nz, int delta) 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++) for (; zig <= this.zigEnd; zig++)
{ {
int u = this.pointers.Unzig[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? // TODO: Are the equality comparsions OK with floating point values? Isn't an epsilon value necessary?
if (bu == 0) if (bu == 0)
@ -662,16 +666,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
continue; continue;
} }
if (bu >= 0) int val = bu >= 0 ? bu + delta : bu - delta;
{
// b[u] += delta; Block8x8.SetScalarAt(b, u, (short)val);
Block8x8F.SetScalarAt(b, u, bu + delta);
} //if (bu >= 0)
else //{
{ // // b[u] += delta;
// b[u] -= delta; // Block8x8.SetScalarAt(b, u, bu + delta);
Block8x8F.SetScalarAt(b, u, bu - delta); //}
} //else
//{
// // b[u] -= delta;
// Block8x8.SetScalarAt(b, u, bu - delta);
//}
} }
return zig; return zig;

10
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) private static void WriteDataToDqt(byte[] dqt, ref int offset, QuantIndex i, ref Block8x8F quant)
{ {
dqt[offset++] = (byte)i; 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]; dqt[offset++] = (byte)quant[j];
} }
@ -276,7 +276,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// <param name="quant">The quantization table.</param> /// <param name="quant">The quantization table.</param>
private static void InitQuantizationTable(int i, int scale, ref Block8x8F quant) 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]; int x = UnscaledQuant[i, j];
x = ((x * scale) + 50) / 100; x = ((x * scale) + 50) / 100;
@ -576,7 +576,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
HuffIndex h = (HuffIndex)((2 * (int)index) + 1); HuffIndex h = (HuffIndex)((2 * (int)index) + 1);
int runLength = 0; int runLength = 0;
for (int zig = 1; zig < Block8x8F.ScalarCount; zig++) for (int zig = 1; zig < Block8x8F.Size; zig++)
{ {
int ac = (int)unziggedDestPtr[zig]; int ac = (int)unziggedDestPtr[zig];
@ -660,12 +660,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
private void WriteDefineQuantizationTables() private void WriteDefineQuantizationTables()
{ {
// Marker + quantization table lengths // Marker + quantization table lengths
int markerlen = 2 + (QuantizationTableCount * (1 + Block8x8F.ScalarCount)); int markerlen = 2 + (QuantizationTableCount * (1 + Block8x8F.Size));
this.WriteMarkerHeader(OldJpegConstants.Markers.DQT, markerlen); this.WriteMarkerHeader(OldJpegConstants.Markers.DQT, markerlen);
// Loop through and collect the tables as one array. // Loop through and collect the tables as one array.
// This allows us to reduce the number of writes to the stream. // 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<byte>.Shared.Rent(dqtCount); byte[] dqt = ArrayPool<byte>.Shared.Rent(dqtCount);
int offset = 0; int offset = 0;

20
src/ImageSharp/Formats/Jpeg/GolangPort/OldJpegDecoderCore.cs

@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.configuration = configuration ?? Configuration.Default; this.configuration = configuration ?? Configuration.Default;
this.HuffmanTrees = OldHuffmanTree.CreateHuffmanTrees(); this.HuffmanTrees = OldHuffmanTree.CreateHuffmanTrees();
this.QuantizationTables = new Block8x8F[MaxTq + 1]; this.QuantizationTables = new Block8x8F[MaxTq + 1];
this.Temp = new byte[2 * Block8x8F.ScalarCount]; this.Temp = new byte[2 * Block8x8F.Size];
} }
/// <summary> /// <summary>
@ -252,7 +252,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
} }
/// <summary> /// <summary>
/// Read metadata from stream and read the blocks in the scans into <see cref="DecodedBlocks"/>. /// Read metadata from stream and read the blocks in the scans into <see cref="OldComponent.SpectralBlocks"/>.
/// </summary> /// </summary>
/// <param name="metadata">The metadata</param> /// <param name="metadata">The metadata</param>
/// <param name="stream">The stream</param> /// <param name="stream">The stream</param>
@ -1113,32 +1113,32 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
switch (x >> 4) switch (x >> 4)
{ {
case 0: case 0:
if (remaining < Block8x8F.ScalarCount) if (remaining < Block8x8F.Size)
{ {
done = true; done = true;
break; break;
} }
remaining -= Block8x8F.ScalarCount; remaining -= Block8x8F.Size;
this.InputProcessor.ReadFull(this.Temp, 0, Block8x8F.ScalarCount); 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]; this.QuantizationTables[tq][i] = this.Temp[i];
} }
break; break;
case 1: case 1:
if (remaining < 2 * Block8x8F.ScalarCount) if (remaining < 2 * Block8x8F.Size)
{ {
done = true; done = true;
break; break;
} }
remaining -= 2 * Block8x8F.ScalarCount; remaining -= 2 * Block8x8F.Size;
this.InputProcessor.ReadFull(this.Temp, 0, 2 * Block8x8F.ScalarCount); 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]; this.QuantizationTables[tq][i] = (this.Temp[2 * i] << 8) | this.Temp[(2 * i) + 1];
} }

14
tests/ImageSharp.Benchmarks/General/RoundSinglePrecisionBlocks.cs

@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General
[GlobalSetup] [GlobalSetup]
public void Setup() 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.inputDividend[i] = i*44.8f;
this.inputDivisior[i] = 100 - i; this.inputDivisior[i] = 100 - i;
@ -44,18 +44,18 @@ namespace SixLabors.ImageSharp.Benchmarks.General
float* pDividend = (float*)&b1; float* pDividend = (float*)&b1;
float* pDivisor = (float*)&b2; float* pDivisor = (float*)&b2;
int* result = stackalloc int[Block8x8F.ScalarCount]; int* result = stackalloc int[Block8x8F.Size];
for (int cnt = 0; cnt < ExecutionCount; cnt++) for (int cnt = 0; cnt < ExecutionCount; cnt++)
{ {
sum = 0; sum = 0;
for (int i = 0; i < Block8x8F.ScalarCount; i++) for (int i = 0; i < Block8x8F.Size; i++)
{ {
int a = (int) pDividend[i]; int a = (int) pDividend[i];
int b = (int) pDivisor; int b = (int) pDivisor;
result[i] = RationalRound(a, b); result[i] = RationalRound(a, b);
} }
for (int i = 0; i < Block8x8F.ScalarCount; i++) for (int i = 0; i < Block8x8F.Size; i++)
{ {
sum += result[i]; sum += result[i];
} }
@ -77,12 +77,12 @@ namespace SixLabors.ImageSharp.Benchmarks.General
for (int cnt = 0; cnt < ExecutionCount; cnt++) for (int cnt = 0; cnt < ExecutionCount; cnt++)
{ {
sum = 0; sum = 0;
for (int i = 0; i < Block8x8F.ScalarCount; i++) for (int i = 0; i < Block8x8F.Size; i++)
{ {
double value = pDividend[i] / pDivisor[i]; double value = pDividend[i] / pDivisor[i];
pDividend[i] = (float) System.Math.Round(value); 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]; sum += (int) pDividend[i];
} }
@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General
{ {
sum = 0; sum = 0;
DivideRoundAll(ref bDividend, ref bDivisor); 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]; sum += (int)pDividend[i];
} }

13
tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs

@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Tests
for (int i = 0; i < Block8x8.Size; i++) for (int i = 0; i < Block8x8.Size; i++)
{ {
Block8x8.SetScalarAt(&block, i, i); Block8x8.SetScalarAt(&block, i, (short)i);
} }
sum = 0; sum = 0;
@ -76,5 +76,16 @@ namespace SixLabors.ImageSharp.Tests
Assert.Equal((float)data[i], dest[i]); 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);
}
} }
} }
Loading…
Cancel
Save