diff --git a/src/ImageSharp46/Formats/Jpg/Components/Block.cs b/src/ImageSharp46/Formats/Jpg/Components/Block.cs
index f41e615b5a..d9b16a44ed 100644
--- a/src/ImageSharp46/Formats/Jpg/Components/Block.cs
+++ b/src/ImageSharp46/Formats/Jpg/Components/Block.cs
@@ -12,9 +12,9 @@ namespace ImageSharp.Formats
///
/// Represents an 8x8 block of coefficients to transform and encode.
///
- public struct Block : IDisposable
+ internal struct Block : IDisposable
{
- private static ArrayPool IntArrayPool = ArrayPool.Create(BlockSize, 50);
+ private static readonly ArrayPool ArrayPool = ArrayPool.Create(BlockSize, 50);
///
/// Gets the size of the block.
@@ -37,7 +37,7 @@ namespace ImageSharp.Formats
public void Init()
{
//this.Data = new int[BlockSize];
- this.Data = IntArrayPool.Rent(BlockSize);
+ this.Data = ArrayPool.Rent(BlockSize);
}
public static Block Create()
@@ -79,7 +79,7 @@ namespace ImageSharp.Formats
{
if (Data != null)
{
- IntArrayPool.Return(Data, true);
+ ArrayPool.Return(Data, true);
Data = null;
}
}
@@ -108,4 +108,103 @@ namespace ImageSharp.Formats
return clone;
}
}
+
+ internal struct BlockF : IDisposable
+ {
+ private static readonly ArrayPool ArrayPool = ArrayPool.Create(BlockSize, 50);
+
+ ///
+ /// Gets the size of the block.
+ ///
+ public const int BlockSize = 64;
+
+ ///
+ /// The array of block data.
+ ///
+ public float[] Data;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ //public Block()
+ //{
+ // this.data = new int[BlockSize];
+ //}
+
+ public void Init()
+ {
+ //this.Data = new int[BlockSize];
+ this.Data = ArrayPool.Rent(BlockSize);
+ }
+
+ public static BlockF Create()
+ {
+ var block = new BlockF();
+ block.Init();
+ return block;
+ }
+
+ public static BlockF[] CreateArray(int size)
+ {
+ BlockF[] result = new BlockF[size];
+ for (int i = 0; i < result.Length; i++)
+ {
+ result[i].Init();
+ }
+ return result;
+ }
+
+ public bool IsInitialized => this.Data != null;
+
+ ///
+ /// Gets the pixel data at the given block index.
+ ///
+ /// The index of the data to return.
+ ///
+ /// The .
+ ///
+ public float this[int index]
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return this.Data[index]; }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set { this.Data[index] = value; }
+ }
+
+ // TODO: Refactor Block.Dispose() callers to always use 'using' or 'finally' statement!
+ public void Dispose()
+ {
+ if (Data != null)
+ {
+ ArrayPool.Return(Data, true);
+ Data = null;
+ }
+ }
+
+ public static void DisposeAll(BlockF[] blocks)
+ {
+ for (int i = 0; i < blocks.Length; i++)
+ {
+ blocks[i].Dispose();
+ }
+ }
+
+
+ public void Clear()
+ {
+ for (int i = 0; i < Data.Length; i++)
+ {
+ Data[i] = 0;
+ }
+ }
+
+ public BlockF Clone()
+ {
+ BlockF clone = Create();
+ Array.Copy(Data, clone.Data, BlockSize);
+ return clone;
+ }
+ }
+
+
}
diff --git a/src/ImageSharp46/Formats/Jpg/Components/Block8x8.cs b/src/ImageSharp46/Formats/Jpg/Components/Block8x8.cs
index 123b2efe56..4e7bef5368 100644
--- a/src/ImageSharp46/Formats/Jpg/Components/Block8x8.cs
+++ b/src/ImageSharp46/Formats/Jpg/Components/Block8x8.cs
@@ -189,6 +189,15 @@ namespace ImageSharp.Formats
dest.MultiplyAllInplace(_0_125);
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void IDCTInplace()
+ {
+ Block8x8 result = new Block8x8();
+ Block8x8 temp = new Block8x8();
+ IDCTInto(ref result, ref temp);
+ this = result;
+ }
+
private static readonly Vector4 _1_175876 = new Vector4(1.175876f);
private static readonly Vector4 _1_961571 = new Vector4(-1.961571f);
private static readonly Vector4 _0_390181 = new Vector4(-0.390181f);
@@ -416,8 +425,8 @@ namespace ImageSharp.Formats
for(i = 0;i < 8;i++){ x[i] *= 0.353554f; }
*/
}
-
- public static void SuchIDCT(ref Block block)
+
+ internal static void SuchIDCT(ref Block block)
{
Block8x8 source = new Block8x8();
source.LoadFrom(block.Data);
@@ -429,6 +438,18 @@ namespace ImageSharp.Formats
dest.CopyTo(block.Data);
}
+ internal static void SuchIDCT(ref BlockF block)
+ {
+ Block8x8 source = new Block8x8();
+ source.LoadFrom(block.Data);
+
+ Block8x8 dest = new Block8x8();
+ Block8x8 temp = new Block8x8();
+
+ source.IDCTInto(ref dest, ref temp);
+ dest.CopyTo(block.Data);
+ }
+
public unsafe float this[int idx]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
diff --git a/src/ImageSharp46/Formats/Jpg/Components/ReferenceDCT.cs b/src/ImageSharp46/Formats/Jpg/Components/ReferenceDCT.cs
index a83ec5d4c1..595a3e54a7 100644
--- a/src/ImageSharp46/Formats/Jpg/Components/ReferenceDCT.cs
+++ b/src/ImageSharp46/Formats/Jpg/Components/ReferenceDCT.cs
@@ -215,7 +215,7 @@ namespace ImageSharp.Formats
}
}
- public static void IDCT(ref Block block)
+ internal static void IDCT(ref Block block)
{
Span src = Span.RentFromPool(64);
diff --git a/src/ImageSharp46/Formats/Jpg/JpegDecoderCore.cs b/src/ImageSharp46/Formats/Jpg/JpegDecoderCore.cs
index 25e0a0d1b3..e66d42d80c 100644
--- a/src/ImageSharp46/Formats/Jpg/JpegDecoderCore.cs
+++ b/src/ImageSharp46/Formats/Jpg/JpegDecoderCore.cs
@@ -84,7 +84,7 @@ namespace ImageSharp.Formats
///
/// Saved state between progressive-mode scans.
///
- private readonly Block[][] progCoeffs;
+ private readonly BlockF[][] progCoeffs;
///
/// The huffman trees
@@ -96,7 +96,7 @@ namespace ImageSharp.Formats
///
/// Quantization tables, in zigzag order.
///
- private readonly Block[] quantizationTables;
+ private readonly BlockF[] quantizationTables;
///
/// A temporary buffer for holding pixels
@@ -201,12 +201,12 @@ namespace ImageSharp.Formats
public JpegDecoderCore()
{
//this.huffmanTrees = new Huffman[MaxTc + 1, MaxTh + 1];
- this.huffmanTrees = new Huffman[(MaxTc + 1)*(MaxTh + 1)];
+ this.huffmanTrees = new Huffman[(MaxTc + 1) * (MaxTh + 1)];
- this.quantizationTables = Block.CreateArray(MaxTq + 1);
- this.temp = new byte[2 * Block.BlockSize];
+ this.quantizationTables = BlockF.CreateArray(MaxTq + 1);
+ this.temp = new byte[2 * BlockF.BlockSize];
this.componentArray = new Component[MaxComponents];
- this.progCoeffs = new Block[MaxComponents][];
+ this.progCoeffs = new BlockF[MaxComponents][];
this.bits = new Bits();
this.bytes = new Bytes();
@@ -217,7 +217,7 @@ namespace ImageSharp.Formats
for (int j = 0; j < MaxTh + 1; j++)
{
//this.huffmanTrees[i, j].Init(LutSize, MaxNCodes, MaxCodeLength);
- this.huffmanTrees[i* ThRowSize + j].Init(LutSize, MaxNCodes, MaxCodeLength);
+ this.huffmanTrees[i * ThRowSize + j].Init(LutSize, MaxNCodes, MaxCodeLength);
}
}
@@ -515,7 +515,7 @@ namespace ImageSharp.Formats
throw new ImageFormatException("Bad Th value");
}
- ProcessDefineHuffmanTablesMarkerLoop(ref this.huffmanTrees[tc* ThRowSize + th], ref remaining);
+ ProcessDefineHuffmanTablesMarkerLoop(ref this.huffmanTrees[tc * ThRowSize + th], ref remaining);
}
}
@@ -571,8 +571,8 @@ namespace ImageSharp.Formats
// whose codeLength's high bits matches code.
// The high 8 bits of lutValue are the encoded value.
// The low 8 bits are 1 plus the codeLength.
- byte base2 = (byte) (code << (7 - i));
- ushort lutValue = (ushort) ((huffman.Values[x] << 8) | (2 + i));
+ byte base2 = (byte)(code << (7 - i));
+ ushort lutValue = (ushort)((huffman.Values[x] << 8) | (2 + i));
for (int k = 0; k < 1 << (7 - i); k++)
{
@@ -1117,32 +1117,32 @@ namespace ImageSharp.Formats
switch (x >> 4)
{
case 0:
- if (remaining < Block.BlockSize)
+ if (remaining < BlockF.BlockSize)
{
done = true;
break;
}
- remaining -= Block.BlockSize;
- this.ReadFull(this.temp, 0, Block.BlockSize);
+ remaining -= BlockF.BlockSize;
+ this.ReadFull(this.temp, 0, BlockF.BlockSize);
- for (int i = 0; i < Block.BlockSize; i++)
+ for (int i = 0; i < BlockF.BlockSize; i++)
{
this.quantizationTables[tq][i] = this.temp[i];
}
break;
case 1:
- if (remaining < 2 * Block.BlockSize)
+ if (remaining < 2 * BlockF.BlockSize)
{
done = true;
break;
}
- remaining -= 2 * Block.BlockSize;
- this.ReadFull(this.temp, 0, 2 * Block.BlockSize);
+ remaining -= 2 * BlockF.BlockSize;
+ this.ReadFull(this.temp, 0, 2 * BlockF.BlockSize);
- for (int i = 0; i < Block.BlockSize; i++)
+ for (int i = 0; i < BlockF.BlockSize; i++)
{
this.quantizationTables[tq][i] = (this.temp[2 * i] << 8) | this.temp[(2 * i) + 1];
}
@@ -1471,7 +1471,7 @@ namespace ImageSharp.Formats
}
}
- private Block scanWorkerBlock = Block.Create();
+ private BlockF scanWorkerBlock = BlockF.Create();
///
/// Processes the SOS (Start of scan marker).
@@ -1535,7 +1535,7 @@ namespace ImageSharp.Formats
// significant bit.
// For baseline JPEGs, these parameters are hard-coded to 0/63/0/0.
int zigStart = 0;
- int zigEnd = Block.BlockSize - 1;
+ int zigEnd = BlockF.BlockSize - 1;
int ah = 0;
int al = 0;
@@ -1546,7 +1546,7 @@ namespace ImageSharp.Formats
ah = this.temp[3 + scanComponentCountX2] >> 4;
al = this.temp[3 + scanComponentCountX2] & 0x0f;
- if ((zigStart == 0 && zigEnd != 0) || zigStart > zigEnd || Block.BlockSize <= zigEnd)
+ if ((zigStart == 0 && zigEnd != 0) || zigStart > zigEnd || BlockF.BlockSize <= zigEnd)
{
throw new ImageFormatException("Bad spectral selection bounds");
}
@@ -1580,7 +1580,7 @@ namespace ImageSharp.Formats
int compIndex = scan[i].Index;
if (this.progCoeffs[compIndex] == null)
{
- this.progCoeffs[compIndex] = Block.CreateArray(mxx * myy * this.componentArray[compIndex].HorizontalFactor * this.componentArray[compIndex].VerticalFactor);
+ this.progCoeffs[compIndex] = BlockF.CreateArray(mxx * myy * this.componentArray[compIndex].HorizontalFactor * this.componentArray[compIndex].VerticalFactor);
for (int j = 0; j < this.progCoeffs[compIndex].Length; j++)
{
@@ -1612,7 +1612,7 @@ namespace ImageSharp.Formats
int compIndex = scan[i].Index;
int hi = this.componentArray[compIndex].HorizontalFactor;
int vi = this.componentArray[compIndex].VerticalFactor;
-
+
for (int j = 0; j < hi * vi; j++)
{
@@ -1656,12 +1656,12 @@ namespace ImageSharp.Formats
}
var qtIndex = this.componentArray[compIndex].Selector;
-
+
if (this.isProgressive) // Load the previous partially decoded coefficients, if applicable.
{
blockIndex = ((@by * mxx) * hi) + bx;
- ProcessBlockImpl(ah,
- ref this.progCoeffs[compIndex][blockIndex],
+ ProcessBlockImpl(ah,
+ ref this.progCoeffs[compIndex][blockIndex],
scan, i, zigStart, zigEnd, al, dc, compIndex, @by, mxx, hi, bx,
ref this.quantizationTables[qtIndex]
);
@@ -1670,11 +1670,11 @@ namespace ImageSharp.Formats
{
//var b = Block.Create();
scanWorkerBlock.Clear();
-
+
ProcessBlockImpl(ah, ref scanWorkerBlock, scan, i, zigStart, zigEnd, al, dc, compIndex, @by, mxx, hi,
bx, ref this.quantizationTables[qtIndex]
);
-
+
//b.Dispose();
}
}
@@ -1718,8 +1718,8 @@ namespace ImageSharp.Formats
// for my
}
- private void ProcessBlockImpl(int ah, ref Block b, Scan[] scan, int i, int zigStart, int zigEnd, int al,
- int[] dc, int compIndex, int @by, int mxx, int hi, int bx, ref Block qt)
+ private void ProcessBlockImpl(int ah, ref BlockF b, Scan[] scan, int i, int zigStart, int zigEnd, int al,
+ int[] dc, int compIndex, int @by, int mxx, int hi, int bx, ref BlockF qt)
{
if (ah != 0)
{
@@ -1755,8 +1755,8 @@ namespace ImageSharp.Formats
for (; zig <= zigEnd; zig++)
{
byte value = this.DecodeHuffman(ref this.huffmanTrees[AcTable * ThRowSize + scan[i].AcTableSelector]);
- byte val0 = (byte) (value >> 4);
- byte val1 = (byte) (value & 0x0f);
+ byte val0 = (byte)(value >> 4);
+ byte val1 = (byte)(value & 0x0f);
if (val1 != 0)
{
zig += val0;
@@ -1772,10 +1772,10 @@ namespace ImageSharp.Formats
{
if (val0 != 0x0f)
{
- this.eobRun = (ushort) (1 << val0);
+ this.eobRun = (ushort)(1 << val0);
if (val0 != 0)
{
- this.eobRun |= (ushort) this.DecodeBits(val0);
+ this.eobRun |= (ushort)this.DecodeBits(val0);
}
this.eobRun--;
@@ -1790,11 +1790,11 @@ namespace ImageSharp.Formats
if (this.isProgressive)
{
- if (zigEnd != Block.BlockSize - 1 || al != 0)
+ if (zigEnd != BlockF.BlockSize - 1 || al != 0)
{
// We haven't completely decoded this 8x8 block. Save the coefficients.
-
- this.progCoeffs[compIndex][((@by*mxx)*hi) + bx] = b.Clone();
+
+ this.progCoeffs[compIndex][((@by * mxx) * hi) + bx] = b.Clone();
// At this point, we could execute the rest of the loop body to dequantize and
// perform the inverse DCT, to save early stages of a progressive image to the
@@ -1806,7 +1806,7 @@ namespace ImageSharp.Formats
}
// Dequantize, perform the inverse DCT and store the block to the image.
- for (int zig = 0; zig < Block.BlockSize; zig++)
+ for (int zig = 0; zig < BlockF.BlockSize; zig++)
{
b[Unzig[zig]] *= qt[zig];
}
@@ -1824,7 +1824,7 @@ namespace ImageSharp.Formats
{
dst = this.grayImage.Pixels;
stride = this.grayImage.Stride;
- offset = this.grayImage.Offset + (8*((@by*this.grayImage.Stride) + bx));
+ offset = this.grayImage.Offset + (8 * ((@by * this.grayImage.Stride) + bx));
}
else
{
@@ -1833,26 +1833,26 @@ namespace ImageSharp.Formats
case 0:
dst = this.ycbcrImage.YChannel;
stride = this.ycbcrImage.YStride;
- offset = this.ycbcrImage.YOffset + (8*((@by*this.ycbcrImage.YStride) + bx));
+ offset = this.ycbcrImage.YOffset + (8 * ((@by * this.ycbcrImage.YStride) + bx));
break;
case 1:
dst = this.ycbcrImage.CbChannel;
stride = this.ycbcrImage.CStride;
- offset = this.ycbcrImage.COffset + (8*((@by*this.ycbcrImage.CStride) + bx));
+ offset = this.ycbcrImage.COffset + (8 * ((@by * this.ycbcrImage.CStride) + bx));
break;
case 2:
dst = this.ycbcrImage.CrChannel;
stride = this.ycbcrImage.CStride;
- offset = this.ycbcrImage.COffset + (8*((@by*this.ycbcrImage.CStride) + bx));
+ offset = this.ycbcrImage.COffset + (8 * ((@by * this.ycbcrImage.CStride) + bx));
break;
case 3:
dst = this.blackPixels;
stride = this.blackStride;
- offset = 8*((@by*this.blackStride) + bx);
+ offset = 8 * ((@by * this.blackStride) + bx);
break;
default:
@@ -1863,12 +1863,12 @@ namespace ImageSharp.Formats
// Level shift by +128, clip to [0, 255], and write to dst.
for (int y = 0; y < 8; y++)
{
- int y8 = y*8;
- int yStride = y*stride;
+ int y8 = y * 8;
+ int yStride = y * stride;
for (int x = 0; x < 8; x++)
{
- int c = b[y8 + x];
+ float c = b[y8 + x];
if (c < -128)
{
c = 0;
@@ -1882,7 +1882,7 @@ namespace ImageSharp.Formats
c += 128;
}
- dst[yStride + x + offset] = (byte) c;
+ dst[yStride + x + offset] = (byte)c;
}
}
}
@@ -1927,15 +1927,15 @@ namespace ImageSharp.Formats
}
- totalHv += currentComponent.HorizontalFactor*currentComponent.VerticalFactor;
+ totalHv += currentComponent.HorizontalFactor * currentComponent.VerticalFactor;
- currentScan.DcTableSelector = (byte) (this.temp[2 + (2*i)] >> 4);
+ currentScan.DcTableSelector = (byte)(this.temp[2 + (2 * i)] >> 4);
if (currentScan.DcTableSelector > MaxTh)
{
throw new ImageFormatException("Bad DC table selector value");
}
- currentScan.AcTableSelector = (byte) (this.temp[2 + (2*i)] & 0x0f);
+ currentScan.AcTableSelector = (byte)(this.temp[2 + (2 * i)] & 0x0f);
if (currentScan.AcTableSelector > MaxTh)
{
throw new ImageFormatException("Bad AC table selector value");
@@ -1950,7 +1950,7 @@ namespace ImageSharp.Formats
/// The zig-zag start index
/// The zig-zag end index
/// The low transform offset
- private void Refine(ref Block b, ref Huffman h, int zigStart, int zigEnd, int delta)
+ private void Refine(ref BlockF b, ref Huffman h, int zigStart, int zigEnd, int delta)
{
// Refining a DC component is trivial.
if (zigStart == 0)
@@ -1963,7 +1963,9 @@ namespace ImageSharp.Formats
bool bit = this.DecodeBit();
if (bit)
{
- b[0] |= delta;
+ int stuff = (int)b[0];
+ stuff |= delta;
+ b[0] = stuff;
}
return;
@@ -2044,7 +2046,7 @@ namespace ImageSharp.Formats
/// The non-zero entry
/// The low transform offset
/// The
- private int RefineNonZeroes(ref Block b, int zig, int zigEnd, int nz, int delta)
+ private int RefineNonZeroes(ref BlockF b, int zig, int zigEnd, int nz, int delta)
{
for (; zig <= zigEnd; zig++)
{
@@ -2264,13 +2266,13 @@ namespace ImageSharp.Formats
public void Dispose()
{
scanWorkerBlock.Dispose();
- Block.DisposeAll(this.quantizationTables);
+ BlockF.DisposeAll(this.quantizationTables);
- foreach (Block[] blocks in progCoeffs)
+ foreach (BlockF[] blocks in progCoeffs)
{
if (blocks != null)
{
- Block.DisposeAll(blocks);
+ BlockF.DisposeAll(blocks);
}
}
diff --git a/tests/ImageSharp.Tests46/Formats/Jpg/Block8x8Tests.cs b/tests/ImageSharp.Tests46/Formats/Jpg/Block8x8Tests.cs
index ae4c32c485..289e390d1b 100644
--- a/tests/ImageSharp.Tests46/Formats/Jpg/Block8x8Tests.cs
+++ b/tests/ImageSharp.Tests46/Formats/Jpg/Block8x8Tests.cs
@@ -73,11 +73,11 @@ namespace ImageSharp.Tests.Formats.Jpg
{
float sum = 0;
- float[] block = new float[64];
+
Measure(Times, () =>
{
//Block8x8 block = new Block8x8();
-
+ float[] block = new float[64];
for (int i = 0; i < Block8x8.ScalarCount; i++)
{
block[i] = i;